diff --git a/.mailmap b/.mailmap index d0d1367a261b..f4f18b06f2f1 100644 --- a/.mailmap +++ b/.mailmap @@ -373,6 +373,7 @@ Jarkko Sakkinen Jason Gunthorpe Jason Gunthorpe Jason Gunthorpe +Jason Wang Jason Xing Javi Merino diff --git a/Documentation/ABI/testing/debugfs-vfio b/Documentation/ABI/testing/debugfs-vfio index 70ec2d454686..ed2f29c3a9b4 100644 --- a/Documentation/ABI/testing/debugfs-vfio +++ b/Documentation/ABI/testing/debugfs-vfio @@ -29,3 +29,29 @@ Date: Oct 2025 KernelVersion: 6.18 Contact: Cédric Le Goater Description: Read the migration features of the vfio device. + +What: /sys/kernel/debug/vfio//pci +Date: June 2026 +KernelVersion: 7.2 +Contact: Alex Williamson +Description: This debugfs file directory is used for debugging + VFIO PCI devices. + +What: /sys/kernel/debug/vfio//pci/nointxmask +Date: June 2026 +KernelVersion: 7.2 +Contact: Alex Williamson +Description: Read the nointxmask policy latched for this device. This + policy governs whether the device may use PCI 2.3 style + INTx masking when supported, reporting a value of "N", or + requires APIC level INTx masking, reporting a value of "Y". + +What: /sys/kernel/debug/vfio//pci/disable_idle_d3 +Date: June 2026 +KernelVersion: 7.2 +Contact: Alex Williamson +Description: Read the disable_idle_d3 policy latched for this device. This + policy governs whether the device PM runtime usage count is + kept elevated while the device is bound to the driver and + unused, reporting a value of "Y", or decremented to allow the + device to enter a low power state, reporting a value of "N". diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index 55ab45f669ac..0da739d9a816 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -251,6 +251,13 @@ Description: RO. Fan 2 speed in RPM. Only supported for particular Intel Xe graphics platforms. + On DG2 the driver always shows two fan channels, because the + FSC_READ_NUM_FANS command does not work on some cards. OEMs + decide how the fans map to tach channels, so two fans can share + one tach line. When that happens, the second channel + reads 0 RPM even though the fan is spinning. This is normal, not + a bug. + What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/fan3_input Date: March 2025 KernelVersion: 6.16 diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml index 4458316326fc..95a5bd894e93 100644 --- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml +++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml @@ -50,7 +50,6 @@ properties: - enum: - mscc,ocelot-spi - mscc,jaguar2-spi - - renesas,rzn1-spi - sophgo,sg2042-spi - thead,th1520-spi - const: snps,dw-apb-ssi @@ -94,6 +93,9 @@ properties: - const: ssi_clk - const: pclk + power-domains: + maxItems: 1 + resets: maxItems: 1 diff --git a/Documentation/filesystems/smb/ksmbd.rst b/Documentation/filesystems/smb/ksmbd.rst index 67cb68ea6e68..672c5d3892ff 100644 --- a/Documentation/filesystems/smb/ksmbd.rst +++ b/Documentation/filesystems/smb/ksmbd.rst @@ -97,7 +97,7 @@ ACLs Partially Supported. only DACLs available, SACLs to allow future support for running as a domain member. Kerberos Supported. -Durable handle v1,v2 Planned for future. +Durable handle v1,v2 Supported. Persistent handle Planned for future. SMB2 notify Planned for future. Sparse file support Supported. @@ -111,7 +111,7 @@ DCE/RPC support Partially Supported. a few calls(NetShareEnumAll, for Witness protocol e.g.) ksmbd/nfsd interoperability Planned for future. The features that ksmbd support are Leases, Notify, ACLs and Share modes. -SMB3.1.1 Compression Planned for future. +SMB3.1.1 Compression Supported. SMB3.1.1 over QUIC Planned for future. Signing/Encryption over RDMA Planned for future. SMB3.1.1 GMAC signing support Planned for future. diff --git a/Documentation/gpu/intel-display/dp-link-training.rst b/Documentation/gpu/intel-display/dp-link-training.rst new file mode 100644 index 000000000000..d0bde965021d --- /dev/null +++ b/Documentation/gpu/intel-display/dp-link-training.rst @@ -0,0 +1,8 @@ +.. SPDX-License-Identifier: MIT +.. Copyright © 2026 Intel Corporation + +DisplayPort Link Training +========================= + +.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_training.c + :doc: DisplayPort link training diff --git a/Documentation/gpu/intel-display/index.rst b/Documentation/gpu/intel-display/index.rst index 01c3d1e576b7..6fa929d82c38 100644 --- a/Documentation/gpu/intel-display/index.rst +++ b/Documentation/gpu/intel-display/index.rst @@ -38,6 +38,7 @@ driver. The display driver isn't an independent driver in that sense. fifo-underrun frontbuffer hotplug + dp-link-training plane psr snps-phy diff --git a/Documentation/hwmon/ltc4283.rst b/Documentation/hwmon/ltc4283.rst index a650c595bc8f..99b1ee05f629 100644 --- a/Documentation/hwmon/ltc4283.rst +++ b/Documentation/hwmon/ltc4283.rst @@ -256,7 +256,7 @@ these logs can be cleared by writing in the proper reset_history attribute. ``/sys/kernel/debug/i2c/i2c-[X]/[X]-addr/`` contains the following attributes: -======================= ========================================== +============================== ========================================================== power1_failed_fault_log Set to 1 by a power1 fault occurring. power1_good_input_fault_log Set to 1 by a power1 good input fault occurring at PGIO3. in11_fet_short_fault_log Set to 1 when a FET-short fault occurs. @@ -264,4 +264,4 @@ in11_fet_bad_fault_log Set to 1 when a FET-BAD fault occurs. in0_lcrit_fault_log Set to 1 by a VIN undervoltage fault occurring. in0_crit_fault_log Set to 1 by a VIN overvoltage fault occurring. curr1_crit_fault_log Set to 1 by an overcurrent fault occurring. -======================= ========================================== +============================== ========================================================== diff --git a/Documentation/sound/codecs/tas675x.rst b/Documentation/sound/codecs/tas675x.rst index c08b0e392306..2d9e009b46b1 100644 --- a/Documentation/sound/codecs/tas675x.rst +++ b/Documentation/sound/codecs/tas675x.rst @@ -281,7 +281,7 @@ Global Temperature :Description: Global die temperature sense register. :Type: Integer (read-only) :Range: 0 to 255 -:Conversion: (value × 0.5 °C) − 50 °C +:Conversion: value × 2.19 K; subtract 273.15 for °C :Register: 0x75 CHx Temperature Range @@ -289,10 +289,11 @@ CHx Temperature Range :Description: Per-channel coarse temperature range indicator (x = 1, 2, 3, 4). :Type: Integer (read-only) -:Range: 0 to 3 -:Mapping: 0 = <80 °C, 1 = 80–100 °C, 2 = 100–120 °C, 3 = >120 °C -:Register: 0xBB bits [7:6] (CH1), bits [5:4] (CH2), - 0xBC bits [3:2] (CH3), bits [1:0] (CH4) +:Range: 0 to 7 +:Mapping: 0 = <95 °C, 1 = 95–110 °C, 2 = 110–125 °C, 3 = 125–135 °C, + 4 = 135–145 °C, 5 = 145–155 °C, 6 = 155–165 °C, 7 = >165 °C +:Register: 0xBB bits [2:0] (CH1), bits [5:3] (CH2), + 0xBC bits [2:0] (CH3), bits [5:3] (CH4) Load Diagnostics ================ diff --git a/MAINTAINERS b/MAINTAINERS index 377d224c5f76..6dea93a41962 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15750,8 +15750,8 @@ F: drivers/net/ethernet/marvell/octeon_ep_vf MARVELL OCTEONTX2 PHYSICAL FUNCTION DRIVER M: Sunil Goutham M: Geetha sowjanya +M: Ratheesh Kannoth M: Subbaraya Sundeep -M: hariprasad M: Bharat Bhushan L: netdev@vger.kernel.org S: Maintained @@ -15760,9 +15760,8 @@ F: include/linux/soc/marvell/octeontx2/ MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER M: Sunil Goutham -M: Linu Cherian +M: Ratheesh Kannoth M: Geetha sowjanya -M: hariprasad M: Subbaraya Sundeep L: netdev@vger.kernel.org S: Maintained @@ -15770,8 +15769,8 @@ F: Documentation/networking/device_drivers/ethernet/marvell/octeontx2.rst F: drivers/net/ethernet/marvell/octeontx2/af/ MARVELL PEM PMU DRIVER -M: Linu Cherian M: Gowthami Thiagarajan +M: Geetha sowjanya S: Supported F: drivers/perf/marvell_pem_pmu.c @@ -18454,6 +18453,7 @@ F: drivers/net/ethernet/mucse/ MULTIFUNCTION DEVICES (MFD) M: Lee Jones +L: mfd@lists.linux.dev S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd.git F: Documentation/devicetree/bindings/mfd/ @@ -25389,6 +25389,7 @@ M: Bard Liao M: Daniel Baluta R: Kai Vehmanen R: Pierre-Louis Bossart +R: Vijendar Mukunda L: sound-open-firmware@alsa-project.org (moderated for non-subscribers) S: Supported W: https://github.com/thesofproject/linux/ @@ -27532,7 +27533,7 @@ F: drivers/net/ethernet/dec/tulip/ TUN/TAP DRIVER M: Willem de Bruijn -M: Jason Wang +M: Jason Wang S: Maintained W: http://vtun.sourceforge.net/tun F: Documentation/networking/tuntap.rst @@ -28524,7 +28525,7 @@ F: include/uapi/linux/virtio_balloon.h VIRTIO BLOCK AND SCSI DRIVERS M: "Michael S. Tsirkin" -M: Jason Wang +M: Jason Wang R: Paolo Bonzini R: Stefan Hajnoczi R: Eugenio Pérez @@ -28553,7 +28554,7 @@ F: include/uapi/linux/virtio_console.h VIRTIO CORE M: "Michael S. Tsirkin" -M: Jason Wang +M: Jason Wang R: Xuan Zhuo R: Eugenio Pérez L: virtualization@lists.linux.dev @@ -28631,7 +28632,7 @@ F: include/uapi/linux/virtio_gpu.h VIRTIO HOST (VHOST) M: "Michael S. Tsirkin" -M: Jason Wang +M: Jason Wang R: Eugenio Pérez L: kvm@vger.kernel.org L: virtualization@lists.linux.dev @@ -28646,7 +28647,7 @@ F: kernel/vhost_task.c VIRTIO HOST (VHOST-SCSI) M: "Michael S. Tsirkin" -M: Jason Wang +M: Jason Wang M: Mike Christie R: Paolo Bonzini R: Stefan Hajnoczi @@ -28686,7 +28687,7 @@ F: include/uapi/linux/virtio_mem.h VIRTIO NET DRIVER M: "Michael S. Tsirkin" -M: Jason Wang +M: Jason Wang R: Xuan Zhuo R: Eugenio Pérez L: netdev@vger.kernel.org @@ -28737,7 +28738,7 @@ F: include/linux/vbox_utils.h F: include/uapi/linux/vbox*.h VIRTUAL BOX SHARED FOLDER VFS DRIVER -M: Hans de Goede +M: Jori Koolstra L: linux-fsdevel@vger.kernel.org S: Maintained F: fs/vboxsf/* diff --git a/Makefile b/Makefile index b9c5792c79e0..b4035d3cef26 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ VERSION = 7 PATCHLEVEL = 2 SUBLEVEL = 0 -EXTRAVERSION = -rc1 +EXTRAVERSION = -rc2 NAME = Baby Opossum Posse # *DOCUMENTATION* diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 68e0baad2bbf..bff673e932fe 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index f6bcc0e1a950..b0075ece4a6e 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -2177,7 +2177,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr image_size = extable_offset + extable_size; ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u64), &header, &image_ptr, - jit_fill_hole); + jit_fill_hole, was_classic); if (!ro_header) goto out_off; @@ -2870,7 +2870,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, void *arch_alloc_bpf_trampoline(unsigned int size) { - return bpf_prog_pack_alloc(size, jit_fill_hole); + return bpf_prog_pack_alloc(size, jit_fill_hole, false); } void arch_free_bpf_trampoline(void *image, unsigned int size) diff --git a/arch/loongarch/kvm/main.c b/arch/loongarch/kvm/main.c index f105a86143f5..3e1005526f4b 100644 --- a/arch/loongarch/kvm/main.c +++ b/arch/loongarch/kvm/main.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index ad7e28375aa9..2738b4db1165 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -1790,7 +1790,7 @@ static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_nodes *tn, void *arch_alloc_bpf_trampoline(unsigned int size) { - return bpf_prog_pack_alloc(size, jit_fill_hole); + return bpf_prog_pack_alloc(size, jit_fill_hole, false); } void arch_free_bpf_trampoline(void *image, unsigned int size) @@ -2256,7 +2256,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr image_size = prog_size + extable_size; /* Now we know the size of the structure to make */ ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32), - &header, &image_ptr, jit_fill_hole); + &header, &image_ptr, jit_fill_hole, + bpf_prog_was_classic(prog)); if (!ro_header) goto out_offset; diff --git a/arch/mips/configs/cu1000-neo_defconfig b/arch/mips/configs/cu1000-neo_defconfig index 19517beaf540..ed2a620e4f86 100644 --- a/arch/mips/configs/cu1000-neo_defconfig +++ b/arch/mips/configs/cu1000-neo_defconfig @@ -86,7 +86,7 @@ CONFIG_DMA_JZ4780=y # CONFIG_INGENIC_TIMER is not set CONFIG_INGENIC_SYSOST=y # CONFIG_IOMMU_SUPPORT is not set -CONFIG_JZ4770_PHY=y +CONFIG_PHY_INGENIC_USB=y CONFIG_EXT4_FS=y # CONFIG_DNOTIFY is not set CONFIG_AUTOFS_FS=y diff --git a/arch/mips/configs/cu1830-neo_defconfig b/arch/mips/configs/cu1830-neo_defconfig index b403e67ab105..9b4aeeef58ce 100644 --- a/arch/mips/configs/cu1830-neo_defconfig +++ b/arch/mips/configs/cu1830-neo_defconfig @@ -89,7 +89,7 @@ CONFIG_DMA_JZ4780=y # CONFIG_INGENIC_TIMER is not set CONFIG_INGENIC_SYSOST=y # CONFIG_IOMMU_SUPPORT is not set -CONFIG_JZ4770_PHY=y +CONFIG_PHY_INGENIC_USB=y CONFIG_EXT4_FS=y # CONFIG_DNOTIFY is not set CONFIG_AUTOFS_FS=y diff --git a/arch/mips/configs/gcw0_defconfig b/arch/mips/configs/gcw0_defconfig index adb9fd62ddb0..6d737810b470 100644 --- a/arch/mips/configs/gcw0_defconfig +++ b/arch/mips/configs/gcw0_defconfig @@ -99,7 +99,7 @@ CONFIG_USB_MUSB_HDRC=y CONFIG_USB_MUSB_GADGET=y CONFIG_USB_MUSB_JZ4740=y CONFIG_USB_INVENTRA_DMA=y -CONFIG_JZ4770_PHY=y +CONFIG_PHY_INGENIC_USB=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 CONFIG_USB_ETH=y diff --git a/arch/mips/dec/platform.c b/arch/mips/dec/platform.c index 723ce16cbfc0..a005246a0ac5 100644 --- a/arch/mips/dec/platform.c +++ b/arch/mips/dec/platform.c @@ -38,6 +38,10 @@ static struct platform_device dec_rtc_device = { .num_resources = ARRAY_SIZE(dec_rtc_resources), }; +static struct platform_device *dec_rtc_devices[] __initdata = { + &dec_rtc_device, +}; + static struct resource dec_dz_resources[] = { { .name = "dz", .flags = IORESOURCE_MEM, }, { .name = "dz", .flags = IORESOURCE_IRQ, }, @@ -137,7 +141,7 @@ static int __init dec_add_devices(void) } num_zs = i; - ret1 = platform_device_register(&dec_rtc_device); + ret1 = platform_add_devices(dec_rtc_devices, 1); ret2 = IS_ENABLED(CONFIG_32BIT) ? platform_add_devices(dec_dz_devices, num_dz) : 0; ret3 = platform_add_devices(dec_zs_devices, num_zs); diff --git a/arch/mips/include/asm/cdmm.h b/arch/mips/include/asm/cdmm.h index 81fa99084178..6e787b7565b7 100644 --- a/arch/mips/include/asm/cdmm.h +++ b/arch/mips/include/asm/cdmm.h @@ -9,7 +9,7 @@ #define __ASM_CDMM_H #include -#include +#include /** * struct mips_cdmm_device - Represents a single device on a CDMM bus. diff --git a/arch/mips/include/asm/irq_work.h b/arch/mips/include/asm/irq_work.h new file mode 100644 index 000000000000..d4fa2d80aabc --- /dev/null +++ b/arch/mips/include/asm/irq_work.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _ASM_MIPS_IRQ_WORK_H +#define _ASM_MIPS_IRQ_WORK_H +static inline bool arch_irq_work_has_interrupt(void) +{ + return IS_ENABLED(CONFIG_MACH_LOONGSON64) && IS_ENABLED(CONFIG_SMP); +} +#endif /* _ASM_MIPS_IRQ_WORK_H */ diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h index 2427d76f953f..a545568f1cac 100644 --- a/arch/mips/include/asm/smp.h +++ b/arch/mips/include/asm/smp.h @@ -50,6 +50,8 @@ extern int __cpu_logical_map[NR_CPUS]; #define SMP_CALL_FUNCTION 0x2 /* Octeon - Tell another core to flush its icache */ #define SMP_ICACHE_FLUSH 0x4 +/* Loongson64 - Self IPI for IRQ work */ +#define SMP_IRQ_WORK 0x8 /* Mask of CPUs which are currently definitely operating coherently */ extern cpumask_t cpu_coherent_mask; diff --git a/arch/mips/lantiq/xway/dcdc.c b/arch/mips/lantiq/xway/dcdc.c index b79c462fd48a..feb73103f009 100644 --- a/arch/mips/lantiq/xway/dcdc.c +++ b/arch/mips/lantiq/xway/dcdc.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c index cbf0639cb3d6..7714c8ee52c4 100644 --- a/arch/mips/lantiq/xway/gptu.c +++ b/arch/mips/lantiq/xway/gptu.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/lantiq/xway/vmmc.c b/arch/mips/lantiq/xway/vmmc.c index 37c133052ef7..e1a0313298ed 100644 --- a/arch/mips/lantiq/xway/vmmc.c +++ b/arch/mips/lantiq/xway/vmmc.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/loongson64/smp.c b/arch/mips/loongson64/smp.c index 147acd972a07..e584299d0fde 100644 --- a/arch/mips/loongson64/smp.c +++ b/arch/mips/loongson64/smp.c @@ -381,6 +381,13 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action) ipi_write_action(cpu_logical_map(i), (u32)action); } +#ifdef CONFIG_IRQ_WORK +void arch_irq_work_raise(void) +{ + loongson3_send_ipi_single(smp_processor_id(), SMP_IRQ_WORK); +} +#endif + static irqreturn_t loongson3_ipi_interrupt(int irq, void *dev_id) { int cpu = smp_processor_id(); @@ -397,6 +404,9 @@ static irqreturn_t loongson3_ipi_interrupt(int irq, void *dev_id) irq_exit(); } + if (action & SMP_IRQ_WORK) + irq_work_run(); + return IRQ_HANDLED; } diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 1c07ca84ee21..352718e43f69 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -426,10 +426,11 @@ static inline void __init highmem_init(void) unsigned long tmp; /* - * If CPU cannot support HIGHMEM discard the memory above highstart_pfn + * If CPU cannot support HIGHMEM discard any memory above highstart_pfn */ if (cpu_has_dc_aliases) { - memblock_remove(PFN_PHYS(highstart_pfn), -1); + if (highstart_pfn) + memblock_remove(PFN_PHYS(highstart_pfn), -1); return; } diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c index 006e2bbab87e..769c89fe1b40 100644 --- a/arch/mips/pci/pci-rt2880.c +++ b/arch/mips/pci/pci-rt2880.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c index 54094f6e033e..06bc2c01420f 100644 --- a/arch/mips/ralink/timer.c +++ b/arch/mips/ralink/timer.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/mips/vdso/elf.S b/arch/mips/vdso/elf.S index a25cb147f1ca..821fcffe7655 100644 --- a/arch/mips/vdso/elf.S +++ b/arch/mips/vdso/elf.S @@ -8,6 +8,7 @@ #include +#include #include #include @@ -15,6 +16,8 @@ ELFNOTE_START(Linux, 0, "a") .long LINUX_VERSION_CODE ELFNOTE_END +BUILD_SALT + /* * The .MIPS.abiflags section must be defined with the FP ABI flags set * to 'any' to be able to link with both old and new libraries. diff --git a/arch/parisc/include/asm/hardware.h b/arch/parisc/include/asm/hardware.h index a005ebc54779..a797c8753f29 100644 --- a/arch/parisc/include/asm/hardware.h +++ b/arch/parisc/include/asm/hardware.h @@ -2,7 +2,7 @@ #ifndef _PARISC_HARDWARE_H #define _PARISC_HARDWARE_H -#include +#include #define HWTYPE_ANY_ID PA_HWTYPE_ANY_ID #define HVERSION_ANY_ID PA_HVERSION_ANY_ID @@ -95,8 +95,6 @@ struct bc_module { #define HPHW_MC 15 #define HPHW_FAULTY 31 -struct parisc_device_id; - /* hardware.c: */ extern const char *parisc_hardware_description(struct parisc_device_id *id); extern enum cpu_type parisc_get_cpu_type(unsigned long hversion); diff --git a/arch/parisc/include/asm/parisc-device.h b/arch/parisc/include/asm/parisc-device.h index 9e74cef4d774..4731420e55ad 100644 --- a/arch/parisc/include/asm/parisc-device.h +++ b/arch/parisc/include/asm/parisc-device.h @@ -3,6 +3,7 @@ #define _ASM_PARISC_PARISC_DEVICE_H_ #include +#include struct parisc_device { struct resource hpa; /* Hard Physical Address */ diff --git a/arch/parisc/include/asm/ptrace.h b/arch/parisc/include/asm/ptrace.h index eea3f3df0823..5e1f52b3922d 100644 --- a/arch/parisc/include/asm/ptrace.h +++ b/arch/parisc/include/asm/ptrace.h @@ -7,6 +7,7 @@ #include #include +#include #define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS)) diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c index d4a17e18c9fb..7b07b43575f1 100644 --- a/arch/powerpc/net/bpf_jit_comp.c +++ b/arch/powerpc/net/bpf_jit_comp.c @@ -295,7 +295,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len; fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image, - bpf_jit_fill_ill_insns); + bpf_jit_fill_ill_insns, bpf_prog_was_classic(fp)); if (!fhdr) goto out_err; @@ -588,7 +588,7 @@ bool bpf_jit_inlines_helper_call(s32 imm) void *arch_alloc_bpf_trampoline(unsigned int size) { - return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns); + return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns, false); } void arch_free_bpf_trampoline(void *image, unsigned int size) diff --git a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c index c3fbec1f1d24..3908c9b0725c 100644 --- a/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c +++ b/arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/platforms/86xx/common.c b/arch/powerpc/platforms/86xx/common.c index a4a550527609..57cb65be7e0f 100644 --- a/arch/powerpc/platforms/86xx/common.c +++ b/arch/powerpc/platforms/86xx/common.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c index 839cf5adc7d9..eea5ed0ce26e 100644 --- a/arch/powerpc/sysdev/fsl_lbc.c +++ b/arch/powerpc/sysdev/fsl_lbc.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c index 9f6dd11c1344..03955a85bed8 100644 --- a/arch/powerpc/sysdev/fsl_pmc.c +++ b/arch/powerpc/sysdev/fsl_pmc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 3f0a647218e4..c0a6992933e4 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -454,7 +454,8 @@ config NR_CPUS range 2 32 if RISCV_SBI_V01 && 32BIT range 2 64 if RISCV_SBI_V01 && 64BIT default "32" if 32BIT - default "64" if 64BIT + default "64" if RISCV_SBI_V01 && 64BIT + default "256" if !RISCV_SBI_V01 && 64BIT config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c index af827448a609..a75f0cfea1e9 100644 --- a/arch/riscv/kernel/asm-offsets.c +++ b/arch/riscv/kernel/asm-offsets.c @@ -501,8 +501,8 @@ void asm_offsets(void) OFFSET(SBI_HART_BOOT_STACK_PTR_OFFSET, sbi_hart_boot_data, stack_ptr); DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN)); - OFFSET(STACKFRAME_FP, stackframe, fp); - OFFSET(STACKFRAME_RA, stackframe, ra); + DEFINE(STACKFRAME_FP, offsetof(struct stackframe, fp) - sizeof(struct stackframe)); + DEFINE(STACKFRAME_RA, offsetof(struct stackframe, ra) - sizeof(struct stackframe)); #ifdef CONFIG_FUNCTION_TRACER DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func)); #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S index c6988983cdf7..08df724e13b9 100644 --- a/arch/riscv/kernel/entry.S +++ b/arch/riscv/kernel/entry.S @@ -386,8 +386,8 @@ SYM_CODE_END(ret_from_fork_user_asm) SYM_FUNC_START(call_on_irq_stack) /* Create a frame record to save ra and s0 (fp) */ addi sp, sp, -STACKFRAME_SIZE_ON_STACK - REG_S ra, STACKFRAME_RA(sp) - REG_S s0, STACKFRAME_FP(sp) + REG_S ra, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_RA)(sp) + REG_S s0, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_FP)(sp) addi s0, sp, STACKFRAME_SIZE_ON_STACK /* Switch to the per-CPU shadow call stack */ @@ -405,8 +405,8 @@ SYM_FUNC_START(call_on_irq_stack) /* Switch back to the thread stack and restore ra and s0 */ addi sp, s0, -STACKFRAME_SIZE_ON_STACK - REG_L ra, STACKFRAME_RA(sp) - REG_L s0, STACKFRAME_FP(sp) + REG_L ra, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_RA)(sp) + REG_L s0, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_FP)(sp) addi sp, sp, STACKFRAME_SIZE_ON_STACK ret diff --git a/arch/riscv/kernel/probes/rethook_trampoline.S b/arch/riscv/kernel/probes/rethook_trampoline.S index f2cd83d9b0f0..c3aa8d8cf5af 100644 --- a/arch/riscv/kernel/probes/rethook_trampoline.S +++ b/arch/riscv/kernel/probes/rethook_trampoline.S @@ -41,6 +41,9 @@ REG_S x29, PT_T4(sp) REG_S x30, PT_T5(sp) REG_S x31, PT_T6(sp) + /* save original sp */ + addi a0, sp, PT_SIZE_ON_STACK + REG_S a0, PT_SP(sp) .endm .macro restore_all_base_regs diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 8b628580fe11..f6ef57930b50 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -189,13 +189,12 @@ int arch_cpuhp_kick_ap_alive(unsigned int cpu, struct task_struct *tidle) #else int __cpu_up(unsigned int cpu, struct task_struct *tidle) { - int ret = 0; + int ret; tidle->thread_info.cpu = cpu; ret = start_secondary_cpu(cpu, tidle); if (!ret) { - wait_for_completion_timeout(&cpu_running, - msecs_to_jiffies(1000)); + wait_for_completion_timeout(&cpu_running, secs_to_jiffies(1)); if (!cpu_online(cpu)) { pr_crit("CPU%u: failed to come online\n", cpu); diff --git a/arch/riscv/kernel/vdso/note.S b/arch/riscv/kernel/vdso/note.S index 3d92cc956b95..69bfe48be037 100644 --- a/arch/riscv/kernel/vdso/note.S +++ b/arch/riscv/kernel/vdso/note.S @@ -4,6 +4,7 @@ * Here we can supply some information useful to userland. */ +#include #include #include #include @@ -12,4 +13,6 @@ ELFNOTE_START(Linux, 0, "a") .long LINUX_VERSION_CODE ELFNOTE_END +BUILD_SALT + emit_riscv_feature_1_and diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c index c03c1de16b79..f9d5347ba966 100644 --- a/arch/riscv/net/bpf_jit_comp64.c +++ b/arch/riscv/net/bpf_jit_comp64.c @@ -1321,7 +1321,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, void *arch_alloc_bpf_trampoline(unsigned int size) { - return bpf_prog_pack_alloc(size, bpf_fill_ill_insns); + return bpf_prog_pack_alloc(size, bpf_fill_ill_insns, false); } void arch_free_bpf_trampoline(void *image, unsigned int size) diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c index 4365d07aaf54..ce3bd3762e08 100644 --- a/arch/riscv/net/bpf_jit_core.c +++ b/arch/riscv/net/bpf_jit_core.c @@ -109,7 +109,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr bpf_jit_binary_pack_alloc(prog_size + extable_size, &jit_data->ro_image, sizeof(u32), &jit_data->header, &jit_data->image, - bpf_fill_ill_insns); + bpf_fill_ill_insns, + bpf_prog_was_classic(prog)); if (!jit_data->ro_header) goto out_offset; diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h index e3afcece375e..d77f26390c07 100644 --- a/arch/s390/include/asm/ccwdev.h +++ b/arch/s390/include/asm/ccwdev.h @@ -10,7 +10,7 @@ #define _S390_CCWDEV_H_ #include -#include +#include #include #include #include diff --git a/arch/sh/drivers/platform_early.c b/arch/sh/drivers/platform_early.c index ca73442a03a6..0ce958d01ba9 100644 --- a/arch/sh/drivers/platform_early.c +++ b/arch/sh/drivers/platform_early.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include -#include +#include #include static __initdata LIST_HEAD(sh_early_platform_driver_list); diff --git a/arch/sparc/crypto/crop_devid.c b/arch/sparc/crypto/crop_devid.c index 93f4e0fdd38c..79a059829a5f 100644 --- a/arch/sparc/crypto/crop_devid.c +++ b/arch/sparc/crypto/crop_devid.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0 -#include +#include #include /* This is a dummy device table linked into all of the crypto diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index b62b1d0291a4..d18f548bbc20 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c index 0b87eb629a62..8c4df33679a1 100644 --- a/arch/sparc/kernel/of_device_64.c +++ b/arch/sparc/kernel/of_device_64.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sparc/kernel/of_device_common.c b/arch/sparc/kernel/of_device_common.c index ba2a6ae23508..7f2f9972b59b 100644 --- a/arch/sparc/kernel/of_device_common.c +++ b/arch/sparc/kernel/of_device_common.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/x86/include/asm/cpu_device_id.h b/arch/x86/include/asm/cpu_device_id.h index 6be777a06944..c62d8fae52c3 100644 --- a/arch/x86/include/asm/cpu_device_id.h +++ b/arch/x86/include/asm/cpu_device_id.h @@ -38,11 +38,8 @@ /* * Declare drivers belonging to specific x86 CPUs * Similar in spirit to pci_device_id and related PCI functions - * - * The wildcard initializers are in mod_devicetable.h because - * file2alias needs them. Sigh. */ -#include +#include /* Get the INTEL_FAM* model defines */ #include /* And the X86_VENDOR_* ones */ diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 4f4b5e8a1574..b68892e6d58c 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -388,6 +388,10 @@ extern void srso_alias_return_thunk(void); extern void entry_untrain_ret(void); extern void write_ibpb(void); +#ifdef CONFIG_BPF_JIT +extern void bpf_arch_ibpb(void); +#endif + #ifdef CONFIG_X86_64 extern void clear_bhb_loop(void); #endif diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 83f51cab0b1e..d9af230c0512 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -1651,8 +1652,21 @@ static inline const char *spectre_v2_module_string(void) { return spectre_v2_bad_module ? " - vulnerable module loaded" : ""; } + +/* + * The "retpoline sequence" is the "call;mov;ret" sequence that + * replaces normal indirect branch instructions. Differentiate + * *the* retpoline sequence from the LFENCE-prefixed indirect + * branches that simply use the retpoline infrastructure. + */ +static inline bool retpoline_seq_enabled(void) +{ + return boot_cpu_has(X86_FEATURE_RETPOLINE) && !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE); +} + #else static inline const char *spectre_v2_module_string(void) { return ""; } +static inline bool retpoline_seq_enabled(void) { return false; } #endif #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n" @@ -2095,8 +2109,7 @@ static void __init bhi_apply_mitigation(void) return; /* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */ - if (boot_cpu_has(X86_FEATURE_RETPOLINE) && - !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) { + if (retpoline_seq_enabled()) { spec_ctrl_disable_kernel_rrsba(); if (rrsba_disabled) return; @@ -2238,6 +2251,27 @@ static void __init spectre_v2_update_mitigation(void) pr_info("%s\n", spectre_v2_strings[spectre_v2_enabled]); } +#ifdef CONFIG_BPF_JIT +static void __bpf_arch_ibpb(void *unused) +{ + write_ibpb(); +} + +void bpf_arch_ibpb(void) +{ + on_each_cpu(__bpf_arch_ibpb, NULL, 1); +} + +static bool __init cpu_wants_ibpb_bpf(void) +{ + /* A genuine retpoline already neutralizes ring0 indirect predictions */ + if (retpoline_seq_enabled()) + return false; + + return boot_cpu_has(X86_FEATURE_IBPB); +} +#endif + static void __init spectre_v2_apply_mitigation(void) { if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled()) @@ -2314,6 +2348,14 @@ static void __init spectre_v2_apply_mitigation(void) setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW); pr_info("Enabling Restricted Speculation for firmware calls\n"); } + +#ifdef CONFIG_BPF_JIT + if (cpu_wants_ibpb_bpf()) { + static_call_update(bpf_arch_pred_flush, bpf_arch_ibpb); + static_branch_enable(&bpf_pred_flush_enabled); + pr_info("Enabling IBPB for BPF\n"); + } +#endif } static void update_stibp_msr(void * __unused) @@ -3490,9 +3532,7 @@ static const char *spectre_bhi_state(void) return "; BHI: BHI_DIS_S"; else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP)) return "; BHI: SW loop, KVM: SW loop"; - else if (boot_cpu_has(X86_FEATURE_RETPOLINE) && - !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) && - rrsba_disabled) + else if (retpoline_seq_enabled() && rrsba_disabled) return "; BHI: Retpoline"; else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_VMEXIT)) return "; BHI: Vulnerable, KVM: SW loop"; diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c index 03ee6102ab07..569894d6e5c8 100644 --- a/arch/x86/kernel/cpu/resctrl/monitor.c +++ b/arch/x86/kernel/cpu/resctrl/monitor.c @@ -259,6 +259,11 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr, if (!domain_header_is_valid(hdr, RESCTRL_MON_DOMAIN, RDT_RESOURCE_L3)) return -EINVAL; + if (cpumask_empty(&hdr->cpu_mask)) { + pr_warn_once("Domain %d has no CPUs\n", hdr->id); + return -EINVAL; + } + d = container_of(hdr, struct rdt_l3_mon_domain, hdr); hw_dom = resctrl_to_arch_mon_dom(d); cpu = cpumask_any(&hdr->cpu_mask); diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index ebb1baf1eb1d..3af979fb41d3 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c @@ -761,9 +761,9 @@ void arch_uprobe_clear_state(struct mm_struct *mm) destroy_uprobe_trampoline(tramp); } -static bool __in_uprobe_trampoline(unsigned long ip) +static bool __in_uprobe_trampoline(struct mm_struct *mm, unsigned long ip) { - struct vm_area_struct *vma = vma_lookup(current->mm, ip); + struct vm_area_struct *vma = vma_lookup(mm, ip); return vma && vma_is_special_mapping(vma, &tramp_mapping); } @@ -776,14 +776,14 @@ static bool in_uprobe_trampoline(unsigned long ip) rcu_read_lock(); if (mmap_lock_speculate_try_begin(mm, &seq)) { - found = __in_uprobe_trampoline(ip); + found = __in_uprobe_trampoline(mm, ip); retry = mmap_lock_speculate_retry(mm, seq); } rcu_read_unlock(); if (retry) { mmap_read_lock(mm); - found = __in_uprobe_trampoline(ip); + found = __in_uprobe_trampoline(mm, ip); mmap_read_unlock(mm); } return found; @@ -1044,7 +1044,7 @@ static int copy_from_vaddr(struct mm_struct *mm, unsigned long vaddr, void *dst, return 0; } -static bool __is_optimized(uprobe_opcode_t *insn, unsigned long vaddr) +static bool __is_optimized(struct mm_struct *mm, uprobe_opcode_t *insn, unsigned long vaddr) { struct __packed __arch_relative_insn { u8 op; @@ -1053,7 +1053,7 @@ static bool __is_optimized(uprobe_opcode_t *insn, unsigned long vaddr) if (!is_call_insn(insn)) return false; - return __in_uprobe_trampoline(vaddr + 5 + call->raddr); + return __in_uprobe_trampoline(mm, vaddr + 5 + call->raddr); } static int is_optimized(struct mm_struct *mm, unsigned long vaddr) @@ -1064,7 +1064,7 @@ static int is_optimized(struct mm_struct *mm, unsigned long vaddr) err = copy_from_vaddr(mm, vaddr, &insn, 5); if (err) return err; - return __is_optimized((uprobe_opcode_t *)&insn, vaddr); + return __is_optimized(mm, (uprobe_opcode_t *)&insn, vaddr); } static bool should_optimize(struct arch_uprobe *auprobe) @@ -1246,9 +1246,15 @@ static int default_post_xol_op(struct arch_uprobe *auprobe, struct pt_regs *regs long correction = utask->vaddr - utask->xol_vaddr; regs->ip += correction; } else if (auprobe->defparam.fixups & UPROBE_FIX_CALL) { + unsigned long retaddr = utask->vaddr + auprobe->defparam.ilen; + int err; + regs->sp += sizeof_long(regs); /* Pop incorrect return address */ - if (emulate_push_stack(regs, utask->vaddr + auprobe->defparam.ilen)) + if (emulate_push_stack(regs, retaddr)) return -ERESTART; + err = shstk_update_last_frame(retaddr); + if (err) + return err; } /* popf; tell the caller to not touch TF */ if (auprobe->defparam.fixups & UPROBE_FIX_SETF) @@ -1338,6 +1344,10 @@ static bool branch_emulate_op(struct arch_uprobe *auprobe, struct pt_regs *regs) */ if (emulate_push_stack(regs, new_ip)) return false; + if (shstk_push(new_ip) == -EFAULT) { + regs->sp += sizeof_long(regs); + return false; + } } else if (!check_jmp_cond(auprobe, regs)) { offs = 0; } diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 9658ce4e0294..4d2bacd00ec4 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -11,7 +11,6 @@ #include "pmu.h" #include -#include #include #include #include diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 2325be57d3d7..cc75feec05da 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 054e043ffcd2..de7515ea1bea 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -3653,7 +3653,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im void *arch_alloc_bpf_trampoline(unsigned int size) { - return bpf_prog_pack_alloc(size, jit_fill_hole); + return bpf_prog_pack_alloc(size, jit_fill_hole, false); } void arch_free_bpf_trampoline(void *image, unsigned int size) @@ -3965,7 +3965,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr /* allocate module memory for x86 insns and extable */ header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size, &image, align, &rw_header, &rw_image, - jit_fill_hole); + jit_fill_hole, + bpf_prog_was_classic(prog)); if (!header) goto out_addrs; prog->aux->extable = (void *) image + roundup(proglen, align); diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c index aab5f70d407c..820af6f0aa57 100644 --- a/arch/x86/xen/mmu_pv.c +++ b/arch/x86/xen/mmu_pv.c @@ -2291,18 +2291,19 @@ static void xen_remap_exchanged_ptes(unsigned long vaddr, int order, } /* - * Perform the hypercall to exchange a region of our pfns to point to - * memory with the required contiguous alignment. Takes the pfns as - * input, and populates mfns as output. + * Perform the hypercall to exchange a region of our pages to point to memory + * with the required contiguous alignment. Takes as input the mfns to trade + * in (mfns_in) and the pfns where the new pages are to appear (fns_inout), + * and populates mfns as output (fns_inout). * * Returns a success code indicating whether the hypervisor was able to * satisfy the request or not. */ static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in, - unsigned long *pfns_in, + unsigned long *mfns_in, unsigned long extents_out, unsigned int order_out, - unsigned long *mfns_out, + unsigned long *fns_inout, unsigned int address_bits) { long rc; @@ -2312,13 +2313,13 @@ static int xen_exchange_memory(unsigned long extents_in, unsigned int order_in, .in = { .nr_extents = extents_in, .extent_order = order_in, - .extent_start = pfns_in, + .extent_start = mfns_in, .domid = DOMID_SELF }, .out = { .nr_extents = extents_out, .extent_order = order_out, - .extent_start = mfns_out, + .extent_start = fns_inout, .address_bits = address_bits, .domid = DOMID_SELF } diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c index e9fbd8c14364..54486960cbf5 100644 --- a/drivers/accel/amdxdna/aie2_ctx.c +++ b/drivers/accel/amdxdna/aie2_ctx.c @@ -59,6 +59,18 @@ static bool aie2_tdr_detect(struct amdxdna_dev *xdna) return false; } +static void aie2_cmd_release(struct kref *ref) +{ + struct amdxdna_drv_cmd *drv_cmd = container_of(ref, struct amdxdna_drv_cmd, refcnt); + + kfree(drv_cmd); +} + +static void aie2_cmd_put(struct amdxdna_drv_cmd *drv_cmd) +{ + kref_put(&drv_cmd->refcnt, aie2_cmd_release); +} + static void aie2_job_release(struct kref *ref) { struct amdxdna_sched_job *job; @@ -70,6 +82,8 @@ static void aie2_job_release(struct kref *ref) wake_up(&job->hwctx->priv->job_free_wq); if (job->out_fence) dma_fence_put(job->out_fence); + if (job->drv_cmd) + aie2_cmd_put(job->drv_cmd); kfree(job->aie2_job_health); kfree(job); } @@ -901,7 +915,7 @@ static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl, { struct amdxdna_client *client = hwctx->client; struct amdxdna_dev *xdna = client->xdna; - struct amdxdna_drv_cmd cmd = { 0 }; + struct amdxdna_drv_cmd *cmd; struct amdxdna_gem_obj *abo; u64 seq; int ret; @@ -912,32 +926,39 @@ static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl, return -EINVAL; } + cmd = kzalloc_obj(*cmd); + if (!cmd) { + ret = -ENOMEM; + goto put_obj; + } + kref_init(&cmd->refcnt); + if (attach) { if (abo->assigned_hwctx != AMDXDNA_INVALID_CTX_HANDLE) { ret = -EBUSY; - goto put_obj; + goto put_cmd; } - cmd.opcode = ATTACH_DEBUG_BO; + cmd->opcode = ATTACH_DEBUG_BO; } else { if (abo->assigned_hwctx != hwctx->id) { ret = -EINVAL; - goto put_obj; + goto put_cmd; } - cmd.opcode = DETACH_DEBUG_BO; + cmd->opcode = DETACH_DEBUG_BO; } - ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE, + ret = amdxdna_cmd_submit(client, cmd, AMDXDNA_INVALID_BO_HANDLE, &bo_hdl, 1, hwctx->id, &seq); if (ret) { XDNA_ERR(xdna, "Submit command failed"); - goto put_obj; + goto put_cmd; } aie2_cmd_wait(hwctx, seq); - if (cmd.result) { - XDNA_ERR(xdna, "Response failure 0x%x", cmd.result); + if (cmd->result) { + XDNA_ERR(xdna, "Response failure 0x%x", cmd->result); ret = -EINVAL; - goto put_obj; + goto put_cmd; } if (attach) @@ -947,6 +968,8 @@ static int aie2_hwctx_cfg_debug_bo(struct amdxdna_hwctx *hwctx, u32 bo_hdl, XDNA_DBG(xdna, "Config debug BO %d to %s", bo_hdl, hwctx->name); +put_cmd: + aie2_cmd_put(cmd); put_obj: amdxdna_gem_put_obj(abo); return ret; @@ -974,25 +997,32 @@ int aie2_hwctx_sync_debug_bo(struct amdxdna_hwctx *hwctx, u32 debug_bo_hdl) { struct amdxdna_client *client = hwctx->client; struct amdxdna_dev *xdna = client->xdna; - struct amdxdna_drv_cmd cmd = { 0 }; + struct amdxdna_drv_cmd *cmd; u64 seq; int ret; - cmd.opcode = SYNC_DEBUG_BO; - ret = amdxdna_cmd_submit(client, &cmd, AMDXDNA_INVALID_BO_HANDLE, + cmd = kzalloc_obj(*cmd); + if (!cmd) + return -ENOMEM; + kref_init(&cmd->refcnt); + + cmd->opcode = SYNC_DEBUG_BO; + ret = amdxdna_cmd_submit(client, cmd, AMDXDNA_INVALID_BO_HANDLE, &debug_bo_hdl, 1, hwctx->id, &seq); if (ret) { XDNA_ERR(xdna, "Submit command failed"); - return ret; + goto put_cmd; } aie2_cmd_wait(hwctx, seq); - if (cmd.result) { - XDNA_ERR(xdna, "Response failure 0x%x", cmd.result); - return -EINVAL; + if (cmd->result) { + XDNA_ERR(xdna, "Response failure 0x%x", cmd->result); + ret = -EINVAL; } - return 0; +put_cmd: + aie2_cmd_put(cmd); + return ret; } static int aie2_populate_range(struct amdxdna_gem_obj *abo) @@ -1142,6 +1172,8 @@ int aie2_cmd_submit(struct amdxdna_hwctx *hwctx, struct amdxdna_sched_job *job, dma_resv_add_fence(job->bos[i]->resv, job->out_fence, DMA_RESV_USAGE_WRITE); job->seq = hwctx->priv->seq++; kref_get(&job->refcnt); + if (job->drv_cmd) + kref_get(&job->drv_cmd->refcnt); drm_sched_entity_push_job(&job->base); *seq = job->seq; diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h index aaae16430466..b6bef3af7dab 100644 --- a/drivers/accel/amdxdna/amdxdna_ctx.h +++ b/drivers/accel/amdxdna/amdxdna_ctx.h @@ -132,6 +132,7 @@ enum amdxdna_job_opcode { struct amdxdna_drv_cmd { enum amdxdna_job_opcode opcode; u32 result; + struct kref refcnt; }; struct app_health_report; diff --git a/drivers/accel/amdxdna/amdxdna_iommu.c b/drivers/accel/amdxdna/amdxdna_iommu.c index eff00131d0f8..4f245b969eef 100644 --- a/drivers/accel/amdxdna/amdxdna_iommu.c +++ b/drivers/accel/amdxdna/amdxdna_iommu.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -153,10 +154,30 @@ void amdxdna_iommu_free(struct amdxdna_dev *xdna, size_t size, free_pages((unsigned long)cpu_addr, get_order(size)); } +static void amdxdna_cleanup_force_iova(struct drm_device *dev, void *res) +{ + struct amdxdna_dev *xdna = to_xdna_dev(dev); + + if (xdna->domain) { + iommu_detach_group(xdna->domain, xdna->group); + put_iova_domain(&xdna->iovad); + iova_cache_put(); + iommu_domain_free(xdna->domain); + } + + iommu_group_put(xdna->group); +} + +void amdxdna_iommu_fini(struct amdxdna_dev *xdna) +{ + if (xdna->group && !xdna->domain) + iommu_group_put(xdna->group); +} + int amdxdna_iommu_init(struct amdxdna_dev *xdna) { unsigned long order; - int ret; + int ret = 0; xdna->group = iommu_group_get(xdna->ddev.dev); if (!xdna->group || !force_iova) @@ -182,8 +203,14 @@ int amdxdna_iommu_init(struct amdxdna_dev *xdna) if (ret) goto put_iova; + ret = drmm_add_action(&xdna->ddev, amdxdna_cleanup_force_iova, NULL); + if (ret) + goto detach_group; + return 0; +detach_group: + iommu_detach_group(xdna->domain, xdna->group); put_iova: put_iova_domain(&xdna->iovad); iova_cache_put(); @@ -191,20 +218,8 @@ int amdxdna_iommu_init(struct amdxdna_dev *xdna) iommu_domain_free(xdna->domain); put_group: iommu_group_put(xdna->group); + xdna->group = NULL; xdna->domain = NULL; return ret; } - -void amdxdna_iommu_fini(struct amdxdna_dev *xdna) -{ - if (xdna->domain) { - iommu_detach_group(xdna->domain, xdna->group); - put_iova_domain(&xdna->iovad); - iova_cache_put(); - iommu_domain_free(xdna->domain); - } - - if (xdna->group) - iommu_group_put(xdna->group); -} diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.c b/drivers/accel/amdxdna/amdxdna_pci_drv.c index 65489bb3f2b0..e94d8290a807 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.c +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.c @@ -138,9 +138,11 @@ static int amdxdna_drm_open(struct drm_device *ddev, struct drm_file *filp) xdna->dev_info->dev_heap_max_size); mutex_init(&client->mm_lock); + mutex_lock(&xdna->client_lock); mutex_lock(&xdna->dev_lock); list_add_tail(&client->node, &xdna->client_list); mutex_unlock(&xdna->dev_lock); + mutex_unlock(&xdna->client_lock); filp->driver_priv = client; client->filp = filp; @@ -174,18 +176,14 @@ static void amdxdna_drm_close(struct drm_device *ddev, struct drm_file *filp) { struct amdxdna_client *client = filp->driver_priv; struct amdxdna_dev *xdna = to_xdna_dev(ddev); - int idx; XDNA_DBG(xdna, "closing pid %d", client->pid); - if (!drm_dev_enter(&xdna->ddev, &idx)) - return; - + mutex_lock(&xdna->client_lock); mutex_lock(&xdna->dev_lock); amdxdna_client_cleanup(client); mutex_unlock(&xdna->dev_lock); - - drm_dev_exit(idx); + mutex_unlock(&xdna->client_lock); } static int amdxdna_drm_get_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) @@ -371,6 +369,10 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!xdna->dev_info) return -ENODEV; + ret = drmm_mutex_init(ddev, &xdna->client_lock); + if (ret) + return ret; + drmm_mutex_init(ddev, &xdna->dev_lock); init_rwsem(&xdna->notifier_lock); INIT_LIST_HEAD(&xdna->client_list); @@ -390,9 +392,9 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) return ret; - xdna->notifier_wq = alloc_ordered_workqueue("notifier_wq", WQ_MEM_RECLAIM); - if (!xdna->notifier_wq) { - ret = -ENOMEM; + xdna->notifier_wq = drmm_alloc_ordered_workqueue(ddev, "notifier_wq", WQ_MEM_RECLAIM); + if (IS_ERR(xdna->notifier_wq)) { + ret = PTR_ERR(xdna->notifier_wq); goto iommu_fini; } @@ -401,7 +403,7 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) mutex_unlock(&xdna->dev_lock); if (ret) { XDNA_ERR(xdna, "Hardware init failed, ret %d", ret); - goto destroy_notifier_wq; + goto iommu_fini; } ret = amdxdna_sysfs_init(xdna); @@ -425,8 +427,6 @@ static int amdxdna_probe(struct pci_dev *pdev, const struct pci_device_id *id) mutex_lock(&xdna->dev_lock); xdna->dev_info->ops->fini(xdna); mutex_unlock(&xdna->dev_lock); -destroy_notifier_wq: - destroy_workqueue(xdna->notifier_wq); iommu_fini: amdxdna_iommu_fini(xdna); return ret; @@ -437,23 +437,19 @@ static void amdxdna_remove(struct pci_dev *pdev) struct amdxdna_dev *xdna = pci_get_drvdata(pdev); struct amdxdna_client *client; - destroy_workqueue(xdna->notifier_wq); - drm_dev_unplug(&xdna->ddev); amdxdna_sysfs_fini(xdna); + mutex_lock(&xdna->client_lock); mutex_lock(&xdna->dev_lock); - client = list_first_entry_or_null(&xdna->client_list, - struct amdxdna_client, node); - while (client) { - amdxdna_client_cleanup(client); - - client = list_first_entry_or_null(&xdna->client_list, - struct amdxdna_client, node); + list_for_each_entry(client, &xdna->client_list, node) { + amdxdna_hwctx_remove_all(client); + amdxdna_sva_fini(client); } xdna->dev_info->ops->fini(xdna); mutex_unlock(&xdna->dev_lock); + mutex_unlock(&xdna->client_lock); amdxdna_iommu_fini(xdna); } diff --git a/drivers/accel/amdxdna/amdxdna_pci_drv.h b/drivers/accel/amdxdna/amdxdna_pci_drv.h index 34271c14d359..a997d27a504d 100644 --- a/drivers/accel/amdxdna/amdxdna_pci_drv.h +++ b/drivers/accel/amdxdna/amdxdna_pci_drv.h @@ -120,6 +120,7 @@ struct amdxdna_dev { struct mutex dev_lock; /* per device lock */ struct list_head client_list; + struct mutex client_lock; /* client_list */ struct amdxdna_fw_ver fw_ver; struct rw_semaphore notifier_lock; /* for mmu notifier*/ struct workqueue_struct *notifier_wq; diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c index fef4713e8061..d121fb0d7732 100644 --- a/drivers/accel/ethosu/ethosu_drv.c +++ b/drivers/accel/ethosu/ethosu_drv.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c index 9faf71f47bdc..45e5f0728ebe 100644 --- a/drivers/accel/qaic/qaic_timesync.c +++ b/drivers/accel/qaic/qaic_timesync.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/accel/qaic/sahara.c b/drivers/accel/qaic/sahara.c index 9fea294e1d7b..c7c0b3eb4b65 100644 --- a/drivers/accel/qaic/sahara.c +++ b/drivers/accel/qaic/sahara.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index 386fc1abcbdc..fc43df083738 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -856,7 +856,7 @@ static int acpi_tad_probe(struct platform_device *pdev) * runtime suspend. Everything else should be taken care of by the ACPI * PM domain callbacks. */ - if (ACPI_TAD_AC_WAKE) { + if (caps & ACPI_TAD_AC_WAKE) { device_init_wakeup(dev, true); dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | DPM_FLAG_MAY_SKIP_RESUME); diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 9a18cdbfd60f..9049bfee409c 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -626,8 +626,6 @@ void acpi_ut_repair_name(char *name); #if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) || defined (ACPI_DEBUG_OUTPUT) u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source); -void acpi_ut_safe_strncpy(char *dest, char *source, acpi_size dest_size); - u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source); u8 diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c index 93867ad7f342..a465e5a1d309 100644 --- a/drivers/acpi/acpica/utnonansi.c +++ b/drivers/acpi/acpica/utnonansi.c @@ -164,20 +164,4 @@ acpi_ut_safe_strncat(char *dest, return (FALSE); } -void acpi_ut_safe_strncpy(char *dest, char *source, acpi_size dest_size) -{ - /* Always terminate destination string */ - -#ifdef __KERNEL__ - strscpy_pad(dest, source, dest_size); -#else - /* - * strscpy_pad() is not defined in ACPICA tools builds, so use strncpy() - * and directly NUL-terminate the destination string in that case. - */ - strncpy(dest, source, dest_size); - dest[dest_size - 1] = 0; -#endif -} - #endif diff --git a/drivers/acpi/riscv/rimt.c b/drivers/acpi/riscv/rimt.c index 906282b0e63c..e4538fa6c2c8 100644 --- a/drivers/acpi/riscv/rimt.c +++ b/drivers/acpi/riscv/rimt.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -257,11 +258,11 @@ static int rimt_iommu_xlate(struct device *dev, struct acpi_rimt_node *node, u32 rimt_fwnode = rimt_get_fwnode(node); /* - * The IOMMU drivers may not be probed yet. - * Defer the IOMMU configuration + * The IOMMU drivers may not be probed yet. Defer the IOMMU + * configuration if it's still in initialization stage. */ if (!rimt_fwnode) - return -EPROBE_DEFER; + return driver_deferred_probe_check_state(dev); /* * EPROBE_DEFER ensures IOMMU is probed before the devices that diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index c18054333f7c..4fbcaff3283c 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index 5d4584570ae0..4490b757abfd 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 3b6243f0f91e..bdc88cf74709 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -2847,6 +2847,24 @@ static void ata_dev_config_cpr(struct ata_device *dev) if (!nr_cpr) goto out; + /* + * The device reports the number of CPR descriptors independently of the + * log size, and that count is also used to emit VPD page B9h into the + * fixed-size rbuf. Reject a count larger than what that buffer can hold + * (ATA_DEV_MAX_CPR) or larger than the log the device actually returned. + */ + if (nr_cpr > ATA_DEV_MAX_CPR) { + ata_dev_warn(dev, + "Too many concurrent positioning ranges\n"); + goto out; + } + + if (buf_len < 64 + (size_t)nr_cpr * 32) { + ata_dev_warn(dev, + "Invalid number of concurrent positioning ranges\n"); + goto out; + } + cpr_log = kzalloc_flex(*cpr_log, cpr, nr_cpr); if (!cpr_log) goto out; @@ -4295,6 +4313,9 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = { /* Apacer models with LPM issues */ { "Apacer AS340*", NULL, ATA_QUIRK_NOLPM }, + /* PNY CS900 (Phison PS3111-S11, DRAM-less) drops the link on DIPM */ + { "PNY CS900 1TB SSD", NULL, ATA_QUIRK_NOLPM }, + /* Silicon Motion models with LPM issues */ { "MD619HXCLDE3TC", "TCVAID", ATA_QUIRK_NOLPM }, { "MD619GXCLDE3TC", "TCV35D", ATA_QUIRK_NOLPM }, diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d54ec1631e9a..5868526301a2 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -37,8 +37,6 @@ #include "libata.h" #include "libata-transport.h" -#define ATA_SCSI_RBUF_SIZE 2048 - static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; @@ -1933,8 +1931,13 @@ static void ata_scsi_rbuf_fill(struct ata_device *dev, struct scsi_cmnd *cmd, memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); len = actor(dev, cmd, ata_scsi_rbuf); if (len) { + if (WARN_ON(len > ATA_SCSI_RBUF_SIZE)) { + ata_scsi_set_sense(dev, cmd, ABORTED_COMMAND, 0, 0); + spin_unlock_irqrestore(&ata_scsi_rbuf_lock, flags); + return; + } sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), - ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + ata_scsi_rbuf, len); cmd->result = SAM_STAT_GOOD; if (scsi_bufflen(cmd) > len) scsi_set_resid(cmd, scsi_bufflen(cmd) - len); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 0dd735c2e5b5..700627596ce1 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -149,6 +149,15 @@ static inline bool ata_acpi_dev_manage_restart(struct ata_device *dev) { return #endif /* libata-scsi.c */ +#define ATA_SCSI_RBUF_SIZE 2048 + +/* + * Maximum number of concurrent positioning ranges (CPR) supported. The ACS + * specifications allow up to 255, but we limit this to the number of CPR + * descriptors that fit in the rbuf buffer used to emit VPD page B9h. + */ +#define ATA_DEV_MAX_CPR min(255, ((ATA_SCSI_RBUF_SIZE - 64) / 32)) + extern struct ata_device *ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); extern int ata_scsi_add_hosts(struct ata_host *host, diff --git a/drivers/ata/pata_buddha.c b/drivers/ata/pata_buddha.c index c36ee991d5e5..b4f019f06b27 100644 --- a/drivers/ata/pata_buddha.c +++ b/drivers/ata/pata_buddha.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/ata/pata_ep93xx.c b/drivers/ata/pata_ep93xx.c index 1663dcd00a93..42a24dc51d26 100644 --- a/drivers/ata/pata_ep93xx.c +++ b/drivers/ata/pata_ep93xx.c @@ -44,7 +44,6 @@ #include #include #include -#include #include diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index b37682b0578f..ad559058cfe6 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #define DRV_NAME "pata_imx" diff --git a/drivers/ata/pata_pxa.c b/drivers/ata/pata_pxa.c index 03dbaf4a13a7..9f63bdfb8576 100644 --- a/drivers/ata/pata_pxa.c +++ b/drivers/ata/pata_pxa.c @@ -286,6 +286,7 @@ static int pxa_ata_probe(struct platform_device *pdev) ret = dmaengine_slave_config(data->dma_chan, &config); if (ret < 0) { dev_err(&pdev->dev, "dma configuration failed: %d\n", ret); + dma_release_channel(data->dma_chan); return ret; } diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c index 530ee26b3012..56ae2820df58 100644 --- a/drivers/ata/sata_gemini.c +++ b/drivers/ata/sata_gemini.c @@ -353,7 +353,7 @@ static int gemini_sata_probe(struct platform_device *pdev) if (sg->ide_pins) { ret = gemini_setup_ide_pins(dev); if (ret) - return ret; + goto out_unprep_clk; } dev_info(dev, "set up the Gemini IDE/SATA nexus\n"); diff --git a/drivers/auxdisplay/arm-charlcd.c b/drivers/auxdisplay/arm-charlcd.c index 30fd2341c628..70efda4f767e 100644 --- a/drivers/auxdisplay/arm-charlcd.c +++ b/drivers/auxdisplay/arm-charlcd.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index b046513987b5..3383d2fcf063 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c index c7a962728752..7b65f4306fae 100644 --- a/drivers/auxdisplay/lcd2s.c +++ b/drivers/auxdisplay/lcd2s.c @@ -13,7 +13,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/auxdisplay/max6959.c b/drivers/auxdisplay/max6959.c index 3bdef099a225..888788a1ff08 100644 --- a/drivers/auxdisplay/max6959.c +++ b/drivers/auxdisplay/max6959.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/auxdisplay/seg-led-gpio.c b/drivers/auxdisplay/seg-led-gpio.c index dfb62e9ce9b4..bc463118fe51 100644 --- a/drivers/auxdisplay/seg-led-gpio.c +++ b/drivers/auxdisplay/seg-led-gpio.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index dca495be0683..f04397b8e381 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -180,7 +180,7 @@ static int print_unex = 1; #include #include /* CMOS defines */ #include -#include +#include #include #include #include diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index c6d9f70ad3bb..93cdde981840 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 244447195619..b2d1ee3a3d11 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/bus/mhi/ep/main.c b/drivers/bus/mhi/ep/main.c index 9db2a2a2c913..b1213786f72c 100644 --- a/drivers/bus/mhi/ep/main.c +++ b/drivers/bus/mhi/ep/main.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "internal.h" diff --git a/drivers/bus/mhi/host/init.c b/drivers/bus/mhi/host/init.c index 0a728ca2c494..12dcb1a2753c 100644 --- a/drivers/bus/mhi/host/init.c +++ b/drivers/bus/mhi/host/init.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/cache/hisi_soc_hha.c b/drivers/cache/hisi_soc_hha.c index 25ff0f5ae79b..756c43398515 100644 --- a/drivers/cache/hisi_soc_hha.c +++ b/drivers/cache/hisi_soc_hha.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/cdx/controller/cdx_controller.c b/drivers/cdx/controller/cdx_controller.c index 280bb7490c0f..960c4f8b6b30 100644 --- a/drivers/cdx/controller/cdx_controller.c +++ b/drivers/cdx/controller/cdx_controller.c @@ -5,7 +5,6 @@ * Copyright (C) 2022-2023, Advanced Micro Devices, Inc. */ -#include #include #include #include diff --git a/drivers/char/hw_random/airoha-trng.c b/drivers/char/hw_random/airoha-trng.c index 9a648f6d9fd4..076519a2f100 100644 --- a/drivers/char/hw_random/airoha-trng.c +++ b/drivers/char/hw_random/airoha-trng.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 6ed24be3481d..4ebbc44fecf0 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/ba431-rng.c b/drivers/char/hw_random/ba431-rng.c index 9de7466e6896..b0a39032c610 100644 --- a/drivers/char/hw_random/ba431-rng.c +++ b/drivers/char/hw_random/ba431-rng.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/bcm74110-rng.c b/drivers/char/hw_random/bcm74110-rng.c index 5c64148e91f1..4ff9ac45202a 100644 --- a/drivers/char/hw_random/bcm74110-rng.c +++ b/drivers/char/hw_random/bcm74110-rng.c @@ -6,7 +6,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include diff --git a/drivers/char/hw_random/exynos-trng.c b/drivers/char/hw_random/exynos-trng.c index 02e207c09e81..1fcc7eb121c2 100644 --- a/drivers/char/hw_random/exynos-trng.c +++ b/drivers/char/hw_random/exynos-trng.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/histb-rng.c b/drivers/char/hw_random/histb-rng.c index 1b91e88cc4c0..445b80beed62 100644 --- a/drivers/char/hw_random/histb-rng.c +++ b/drivers/char/hw_random/histb-rng.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/char/hw_random/imx-rngc.c b/drivers/char/hw_random/imx-rngc.c index 241664a9b5d9..28c56c2d1bf6 100644 --- a/drivers/char/hw_random/imx-rngc.c +++ b/drivers/char/hw_random/imx-rngc.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/char/hw_random/ingenic-trng.c b/drivers/char/hw_random/ingenic-trng.c index 1672320e7d3d..0dbe116346fd 100644 --- a/drivers/char/hw_random/ingenic-trng.c +++ b/drivers/char/hw_random/ingenic-trng.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/iproc-rng200.c b/drivers/char/hw_random/iproc-rng200.c index 440fe28bddc0..2e2aafca5cf0 100644 --- a/drivers/char/hw_random/iproc-rng200.c +++ b/drivers/char/hw_random/iproc-rng200.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index 6959d6edd44c..d797c6020168 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/pic32-rng.c b/drivers/char/hw_random/pic32-rng.c index 888e6f5cec1f..1c764924f2dd 100644 --- a/drivers/char/hw_random/pic32-rng.c +++ b/drivers/char/hw_random/pic32-rng.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/char/hw_random/powernv-rng.c b/drivers/char/hw_random/powernv-rng.c index 47b88de029f2..df5ba90fdb87 100644 --- a/drivers/char/hw_random/powernv-rng.c +++ b/drivers/char/hw_random/powernv-rng.c @@ -6,7 +6,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include diff --git a/drivers/char/hw_random/xgene-rng.c b/drivers/char/hw_random/xgene-rng.c index 709a36507145..1f4b95341c2e 100644 --- a/drivers/char/hw_random/xgene-rng.c +++ b/drivers/char/hw_random/xgene-rng.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/char/hw_random/xilinx-trng.c b/drivers/char/hw_random/xilinx-trng.c index f615d5adddde..0fbc22c38fbc 100644 --- a/drivers/char/hw_random/xilinx-trng.c +++ b/drivers/char/hw_random/xilinx-trng.c @@ -14,7 +14,6 @@ #include #include #include -#include #include /* TRNG Registers Offsets */ diff --git a/drivers/char/hw_random/xiphera-trng.c b/drivers/char/hw_random/xiphera-trng.c index 4af64f76c8d6..ab5d852ff69f 100644 --- a/drivers/char/hw_random/xiphera-trng.c +++ b/drivers/char/hw_random/xiphera-trng.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/aspeed/clk-ast2600.c b/drivers/clk/aspeed/clk-ast2600.c index 873879e5ad9b..70061c961b69 100644 --- a/drivers/clk/aspeed/clk-ast2600.c +++ b/drivers/clk/aspeed/clk-ast2600.c @@ -5,7 +5,6 @@ #define pr_fmt(fmt) "clk-ast2600: " fmt #include -#include #include #include #include diff --git a/drivers/clk/aspeed/clk-ast2700.c b/drivers/clk/aspeed/clk-ast2700.c index 8b7b382f6f3e..aa4dd7f24608 100644 --- a/drivers/clk/aspeed/clk-ast2700.c +++ b/drivers/clk/aspeed/clk-ast2700.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 26f76a6db820..6fcee41447e4 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c index 46251008c83f..122e57176c1c 100644 --- a/drivers/clk/clk-bm1880.c +++ b/drivers/clk/clk-bm1880.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index a495d313b02f..b7063cf5c5c1 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c index d9303c2c7aa5..9743de55bdf8 100644 --- a/drivers/clk/clk-eyeq.c +++ b/drivers/clk/clk-eyeq.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/clk-renesas-pcie.c b/drivers/clk/clk-renesas-pcie.c index aa108df12e44..2f6d80ee77cc 100644 --- a/drivers/clk/clk-renesas-pcie.c +++ b/drivers/clk/clk-renesas-pcie.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index 4ed4e1a5f4f2..ceadc07bcb6d 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index 57228e88e81d..913fcc5675f1 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/imx/clk-imx8mp-audiomix.c b/drivers/clk/imx/clk-imx8mp-audiomix.c index 131702f2c9ec..2225796a9c08 100644 --- a/drivers/clk/imx/clk-imx8mp-audiomix.c +++ b/drivers/clk/imx/clk-imx8mp-audiomix.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/mediatek/clk-mt2701-g3d.c b/drivers/clk/mediatek/clk-mt2701-g3d.c index b3e18b6db75d..a47d6649e4af 100644 --- a/drivers/clk/mediatek/clk-mt2701-g3d.c +++ b/drivers/clk/mediatek/clk-mt2701-g3d.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index d9f40fda73d1..710c4f2f9f30 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -5,7 +5,6 @@ */ #include -#include #include #include "clk-cpumux.h" diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c index 964c92130e3c..6109b55913b3 100644 --- a/drivers/clk/mediatek/clk-mt2712.c +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt6765.c b/drivers/clk/mediatek/clk-mt6765.c index 60f6f9fa7dcf..71956a528fa4 100644 --- a/drivers/clk/mediatek/clk-mt6765.c +++ b/drivers/clk/mediatek/clk-mt6765.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt6779-aud.c b/drivers/clk/mediatek/clk-mt6779-aud.c index 8ed318bd7765..30c290fd6b84 100644 --- a/drivers/clk/mediatek/clk-mt6779-aud.c +++ b/drivers/clk/mediatek/clk-mt6779-aud.c @@ -6,7 +6,6 @@ #include #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt7622-eth.c b/drivers/clk/mediatek/clk-mt7622-eth.c index 1c1033a92c46..c412b04e5ad5 100644 --- a/drivers/clk/mediatek/clk-mt7622-eth.c +++ b/drivers/clk/mediatek/clk-mt7622-eth.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt7622-hif.c b/drivers/clk/mediatek/clk-mt7622-hif.c index 5bcfe12c4fd0..22cf98360d2f 100644 --- a/drivers/clk/mediatek/clk-mt7622-hif.c +++ b/drivers/clk/mediatek/clk-mt7622-hif.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt7622.c b/drivers/clk/mediatek/clk-mt7622.c index f62b03abab4f..a8b3079776bd 100644 --- a/drivers/clk/mediatek/clk-mt7622.c +++ b/drivers/clk/mediatek/clk-mt7622.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-cpumux.h" diff --git a/drivers/clk/mediatek/clk-mt7629-hif.c b/drivers/clk/mediatek/clk-mt7629-hif.c index 3fdc2d7d4274..1dd069fe675c 100644 --- a/drivers/clk/mediatek/clk-mt7629-hif.c +++ b/drivers/clk/mediatek/clk-mt7629-hif.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt7981-apmixed.c b/drivers/clk/mediatek/clk-mt7981-apmixed.c index 6606b54fb376..851d0bc7840a 100644 --- a/drivers/clk/mediatek/clk-mt7981-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7981-apmixed.c @@ -8,7 +8,6 @@ */ #include -#include #include #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt7981-eth.c b/drivers/clk/mediatek/clk-mt7981-eth.c index 0655ebb6c561..d28c1c95c2a3 100644 --- a/drivers/clk/mediatek/clk-mt7981-eth.c +++ b/drivers/clk/mediatek/clk-mt7981-eth.c @@ -8,7 +8,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt7981-infracfg.c b/drivers/clk/mediatek/clk-mt7981-infracfg.c index 0487b6bb80ae..68a102d21380 100644 --- a/drivers/clk/mediatek/clk-mt7981-infracfg.c +++ b/drivers/clk/mediatek/clk-mt7981-infracfg.c @@ -8,7 +8,6 @@ */ #include -#include #include #include "clk-mtk.h" #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt7981-topckgen.c b/drivers/clk/mediatek/clk-mt7981-topckgen.c index 1943f11e47c1..e71ae8fadd5d 100644 --- a/drivers/clk/mediatek/clk-mt7981-topckgen.c +++ b/drivers/clk/mediatek/clk-mt7981-topckgen.c @@ -8,7 +8,6 @@ #include -#include #include #include "clk-mtk.h" #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt7986-apmixed.c b/drivers/clk/mediatek/clk-mt7986-apmixed.c index 1c79418d08a7..af3e002bbfb7 100644 --- a/drivers/clk/mediatek/clk-mt7986-apmixed.c +++ b/drivers/clk/mediatek/clk-mt7986-apmixed.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt7986-eth.c b/drivers/clk/mediatek/clk-mt7986-eth.c index 4514d42c0829..03f14fd85610 100644 --- a/drivers/clk/mediatek/clk-mt7986-eth.c +++ b/drivers/clk/mediatek/clk-mt7986-eth.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt7986-infracfg.c b/drivers/clk/mediatek/clk-mt7986-infracfg.c index 732c65e616de..8e479ca6be7e 100644 --- a/drivers/clk/mediatek/clk-mt7986-infracfg.c +++ b/drivers/clk/mediatek/clk-mt7986-infracfg.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-mtk.h" #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt7986-topckgen.c b/drivers/clk/mediatek/clk-mt7986-topckgen.c index 2dd30da306d9..1489fc58bfdf 100644 --- a/drivers/clk/mediatek/clk-mt7986-topckgen.c +++ b/drivers/clk/mediatek/clk-mt7986-topckgen.c @@ -6,7 +6,6 @@ */ #include -#include #include #include "clk-mtk.h" #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt8167-aud.c b/drivers/clk/mediatek/clk-mt8167-aud.c index d6cff4bdf4cb..6d1057bc6098 100644 --- a/drivers/clk/mediatek/clk-mt8167-aud.c +++ b/drivers/clk/mediatek/clk-mt8167-aud.c @@ -7,7 +7,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8167-img.c b/drivers/clk/mediatek/clk-mt8167-img.c index 42d38ae94b69..0ad163e65e37 100644 --- a/drivers/clk/mediatek/clk-mt8167-img.c +++ b/drivers/clk/mediatek/clk-mt8167-img.c @@ -7,7 +7,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8167-mfgcfg.c b/drivers/clk/mediatek/clk-mt8167-mfgcfg.c index 1ef37a3e6851..2904aea984aa 100644 --- a/drivers/clk/mediatek/clk-mt8167-mfgcfg.c +++ b/drivers/clk/mediatek/clk-mt8167-mfgcfg.c @@ -7,7 +7,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8167-mm.c b/drivers/clk/mediatek/clk-mt8167-mm.c index cef66ee836f3..f9fc003e5c68 100644 --- a/drivers/clk/mediatek/clk-mt8167-mm.c +++ b/drivers/clk/mediatek/clk-mt8167-mm.c @@ -7,7 +7,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8167-vdec.c b/drivers/clk/mediatek/clk-mt8167-vdec.c index e3769bc556a9..f6b681cc1d03 100644 --- a/drivers/clk/mediatek/clk-mt8167-vdec.c +++ b/drivers/clk/mediatek/clk-mt8167-vdec.c @@ -7,7 +7,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8173-mm.c b/drivers/clk/mediatek/clk-mt8173-mm.c index 26d27250b914..9c022378c268 100644 --- a/drivers/clk/mediatek/clk-mt8173-mm.c +++ b/drivers/clk/mediatek/clk-mt8173-mm.c @@ -5,7 +5,6 @@ */ #include -#include #include #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt8183.c b/drivers/clk/mediatek/clk-mt8183.c index aa7cc7709b2d..140fcf524ce6 100644 --- a/drivers/clk/mediatek/clk-mt8183.c +++ b/drivers/clk/mediatek/clk-mt8183.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8188-adsp_audio26m.c b/drivers/clk/mediatek/clk-mt8188-adsp_audio26m.c index dcde2187d24a..36f27401cc87 100644 --- a/drivers/clk/mediatek/clk-mt8188-adsp_audio26m.c +++ b/drivers/clk/mediatek/clk-mt8188-adsp_audio26m.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8188-apmixedsys.c b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c index a1de596bff99..48a2f61d4b77 100644 --- a/drivers/clk/mediatek/clk-mt8188-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8188-apmixedsys.c @@ -5,7 +5,6 @@ */ #include -#include #include #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt8188-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8188-imp_iic_wrap.c index 14a4b575b583..efbd9168edcc 100644 --- a/drivers/clk/mediatek/clk-mt8188-imp_iic_wrap.c +++ b/drivers/clk/mediatek/clk-mt8188-imp_iic_wrap.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8188-topckgen.c b/drivers/clk/mediatek/clk-mt8188-topckgen.c index 6b07abe9a8f5..694d894aaa33 100644 --- a/drivers/clk/mediatek/clk-mt8188-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8188-topckgen.c @@ -5,7 +5,6 @@ */ #include -#include #include #include "clk-gate.h" diff --git a/drivers/clk/mediatek/clk-mt8188-vdo0.c b/drivers/clk/mediatek/clk-mt8188-vdo0.c index 017d6662589b..d7b7d48b6d08 100644 --- a/drivers/clk/mediatek/clk-mt8188-vdo0.c +++ b/drivers/clk/mediatek/clk-mt8188-vdo0.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8188-vdo1.c b/drivers/clk/mediatek/clk-mt8188-vdo1.c index f715d45e545e..c44aa089f83f 100644 --- a/drivers/clk/mediatek/clk-mt8188-vdo1.c +++ b/drivers/clk/mediatek/clk-mt8188-vdo1.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8188-venc.c b/drivers/clk/mediatek/clk-mt8188-venc.c index 01e971545506..250cdadbb28b 100644 --- a/drivers/clk/mediatek/clk-mt8188-venc.c +++ b/drivers/clk/mediatek/clk-mt8188-venc.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8188-wpe.c b/drivers/clk/mediatek/clk-mt8188-wpe.c index d709bb1ee1d6..ab77b250e6db 100644 --- a/drivers/clk/mediatek/clk-mt8188-wpe.c +++ b/drivers/clk/mediatek/clk-mt8188-wpe.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8192-cam.c b/drivers/clk/mediatek/clk-mt8192-cam.c index 891d2f88d9cf..dbae1aca56a9 100644 --- a/drivers/clk/mediatek/clk-mt8192-cam.c +++ b/drivers/clk/mediatek/clk-mt8192-cam.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-img.c b/drivers/clk/mediatek/clk-mt8192-img.c index c08e831125a5..aa38ee8d053d 100644 --- a/drivers/clk/mediatek/clk-mt8192-img.c +++ b/drivers/clk/mediatek/clk-mt8192-img.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c b/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c index 0f9530d9263c..f280f002b8db 100644 --- a/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c +++ b/drivers/clk/mediatek/clk-mt8192-imp_iic_wrap.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-ipe.c b/drivers/clk/mediatek/clk-mt8192-ipe.c index c932b8b20edc..a1f073bf53de 100644 --- a/drivers/clk/mediatek/clk-mt8192-ipe.c +++ b/drivers/clk/mediatek/clk-mt8192-ipe.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-mdp.c b/drivers/clk/mediatek/clk-mt8192-mdp.c index 30334ebca864..fb05866d394f 100644 --- a/drivers/clk/mediatek/clk-mt8192-mdp.c +++ b/drivers/clk/mediatek/clk-mt8192-mdp.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-mfg.c b/drivers/clk/mediatek/clk-mt8192-mfg.c index 9d176659e8a2..0d84ff233215 100644 --- a/drivers/clk/mediatek/clk-mt8192-mfg.c +++ b/drivers/clk/mediatek/clk-mt8192-mfg.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-msdc.c b/drivers/clk/mediatek/clk-mt8192-msdc.c index 04a66220f269..fd7eecfe3077 100644 --- a/drivers/clk/mediatek/clk-mt8192-msdc.c +++ b/drivers/clk/mediatek/clk-mt8192-msdc.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-scp_adsp.c b/drivers/clk/mediatek/clk-mt8192-scp_adsp.c index f9e4c16573e2..256a410ad433 100644 --- a/drivers/clk/mediatek/clk-mt8192-scp_adsp.c +++ b/drivers/clk/mediatek/clk-mt8192-scp_adsp.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-vdec.c b/drivers/clk/mediatek/clk-mt8192-vdec.c index 9c10161807b2..4ce0cfa375a0 100644 --- a/drivers/clk/mediatek/clk-mt8192-vdec.c +++ b/drivers/clk/mediatek/clk-mt8192-vdec.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192-venc.c b/drivers/clk/mediatek/clk-mt8192-venc.c index 0b01e2b7f036..dd87fdea7ae2 100644 --- a/drivers/clk/mediatek/clk-mt8192-venc.c +++ b/drivers/clk/mediatek/clk-mt8192-venc.c @@ -4,7 +4,6 @@ // Author: Chun-Jie Chen #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/mediatek/clk-mt8192.c b/drivers/clk/mediatek/clk-mt8192.c index 12c8890d922f..a1a7caf557fa 100644 --- a/drivers/clk/mediatek/clk-mt8192.c +++ b/drivers/clk/mediatek/clk-mt8192.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c index 44917ab034c5..a120c3305547 100644 --- a/drivers/clk/mediatek/clk-mt8195-apmixedsys.c +++ b/drivers/clk/mediatek/clk-mt8195-apmixedsys.c @@ -10,7 +10,6 @@ #include "clk-pllfh.h" #include -#include #include static const struct mtk_gate_regs apmixed_cg_regs = { diff --git a/drivers/clk/mediatek/clk-mt8195-topckgen.c b/drivers/clk/mediatek/clk-mt8195-topckgen.c index b1f44b873354..b2fecd37cfd4 100644 --- a/drivers/clk/mediatek/clk-mt8195-topckgen.c +++ b/drivers/clk/mediatek/clk-mt8195-topckgen.c @@ -8,7 +8,6 @@ #include "clk-mux.h" #include -#include #include static DEFINE_SPINLOCK(mt8195_clk_lock); diff --git a/drivers/clk/mediatek/clk-mt8365.c b/drivers/clk/mediatek/clk-mt8365.c index e7952121112e..614848c75e3b 100644 --- a/drivers/clk/mediatek/clk-mt8365.c +++ b/drivers/clk/mediatek/clk-mt8365.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/mediatek/clk-mt8516-aud.c b/drivers/clk/mediatek/clk-mt8516-aud.c index 6227635fd5a1..6104ccc34e8d 100644 --- a/drivers/clk/mediatek/clk-mt8516-aud.c +++ b/drivers/clk/mediatek/clk-mt8516-aud.c @@ -7,7 +7,6 @@ */ #include -#include #include #include "clk-mtk.h" diff --git a/drivers/clk/meson/a1-peripherals.c b/drivers/clk/meson/a1-peripherals.c index 5e0d58c01405..43cd6281b719 100644 --- a/drivers/clk/meson/a1-peripherals.c +++ b/drivers/clk/meson/a1-peripherals.c @@ -8,7 +8,6 @@ */ #include -#include #include #include "clk-dualdiv.h" #include "clk-regmap.h" diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c index 1f82e9c7c14e..100c4221256e 100644 --- a/drivers/clk/meson/a1-pll.c +++ b/drivers/clk/meson/a1-pll.c @@ -8,7 +8,6 @@ */ #include -#include #include #include "clk-pll.h" #include "clk-regmap.h" diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c index 0a25c649ef1d..280842e9cb37 100644 --- a/drivers/clk/meson/axg.c +++ b/drivers/clk/meson/axg.c @@ -11,7 +11,6 @@ #include #include -#include #include #include diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index f9131d014ef4..39af7b1868e3 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -6,7 +6,6 @@ #include #include -#include #include #include diff --git a/drivers/clk/qcom/cambistmclkcc-kaanapali.c b/drivers/clk/qcom/cambistmclkcc-kaanapali.c index 6028d8f6959c..c96e9196d908 100644 --- a/drivers/clk/qcom/cambistmclkcc-kaanapali.c +++ b/drivers/clk/qcom/cambistmclkcc-kaanapali.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/cambistmclkcc-sm8750.c b/drivers/clk/qcom/cambistmclkcc-sm8750.c index 5df12aced4a5..69abb756c04f 100644 --- a/drivers/clk/qcom/cambistmclkcc-sm8750.c +++ b/drivers/clk/qcom/cambistmclkcc-sm8750.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-kaanapali.c b/drivers/clk/qcom/camcc-kaanapali.c index af5486418492..50bd19fdaba0 100644 --- a/drivers/clk/qcom/camcc-kaanapali.c +++ b/drivers/clk/qcom/camcc-kaanapali.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-milos.c b/drivers/clk/qcom/camcc-milos.c index 579b71e0e089..8dda816a1369 100644 --- a/drivers/clk/qcom/camcc-milos.c +++ b/drivers/clk/qcom/camcc-milos.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-qcs615.c b/drivers/clk/qcom/camcc-qcs615.c index 8377126c2cfe..db50c0751472 100644 --- a/drivers/clk/qcom/camcc-qcs615.c +++ b/drivers/clk/qcom/camcc-qcs615.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sa8775p.c b/drivers/clk/qcom/camcc-sa8775p.c index 50e5a131261b..914478139e97 100644 --- a/drivers/clk/qcom/camcc-sa8775p.c +++ b/drivers/clk/qcom/camcc-sa8775p.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sc7180.c b/drivers/clk/qcom/camcc-sc7180.c index 5031df813b4a..a69b70ab1a70 100644 --- a/drivers/clk/qcom/camcc-sc7180.c +++ b/drivers/clk/qcom/camcc-sc7180.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sc7280.c b/drivers/clk/qcom/camcc-sc7280.c index 55545f5fdb98..5a9992a5b5ba 100644 --- a/drivers/clk/qcom/camcc-sc7280.c +++ b/drivers/clk/qcom/camcc-sc7280.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sc8180x.c b/drivers/clk/qcom/camcc-sc8180x.c index 016f37d08468..c8b98f81ddef 100644 --- a/drivers/clk/qcom/camcc-sc8180x.c +++ b/drivers/clk/qcom/camcc-sc8180x.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sc8280xp.c b/drivers/clk/qcom/camcc-sc8280xp.c index 18f5a3eb313e..e97b8d4f3c84 100644 --- a/drivers/clk/qcom/camcc-sc8280xp.c +++ b/drivers/clk/qcom/camcc-sc8280xp.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c index fb313da7165b..534dc56fc13c 100644 --- a/drivers/clk/qcom/camcc-sdm845.c +++ b/drivers/clk/qcom/camcc-sdm845.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm4450.c b/drivers/clk/qcom/camcc-sm4450.c index 6170d5ad9cbf..586c1d103132 100644 --- a/drivers/clk/qcom/camcc-sm4450.c +++ b/drivers/clk/qcom/camcc-sm4450.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/clk/qcom/camcc-sm6350.c b/drivers/clk/qcom/camcc-sm6350.c index 7df12c1311c6..9a62228c314c 100644 --- a/drivers/clk/qcom/camcc-sm6350.c +++ b/drivers/clk/qcom/camcc-sm6350.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm7150.c b/drivers/clk/qcom/camcc-sm7150.c index ee963ed341c3..6f75689e9847 100644 --- a/drivers/clk/qcom/camcc-sm7150.c +++ b/drivers/clk/qcom/camcc-sm7150.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm8150.c b/drivers/clk/qcom/camcc-sm8150.c index 62aadb27c50e..fcbaff55fc27 100644 --- a/drivers/clk/qcom/camcc-sm8150.c +++ b/drivers/clk/qcom/camcc-sm8150.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm8250.c b/drivers/clk/qcom/camcc-sm8250.c index c95a00628630..21e942367621 100644 --- a/drivers/clk/qcom/camcc-sm8250.c +++ b/drivers/clk/qcom/camcc-sm8250.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm8450.c b/drivers/clk/qcom/camcc-sm8450.c index 1891262a559b..4025db23d1a9 100644 --- a/drivers/clk/qcom/camcc-sm8450.c +++ b/drivers/clk/qcom/camcc-sm8450.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm8550.c b/drivers/clk/qcom/camcc-sm8550.c index 34d53e2ffad7..aaae5e671905 100644 --- a/drivers/clk/qcom/camcc-sm8550.c +++ b/drivers/clk/qcom/camcc-sm8550.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm8650.c b/drivers/clk/qcom/camcc-sm8650.c index 9dea43e74cb6..3aad816ed233 100644 --- a/drivers/clk/qcom/camcc-sm8650.c +++ b/drivers/clk/qcom/camcc-sm8650.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-sm8750.c b/drivers/clk/qcom/camcc-sm8750.c index 6618b074c90e..4dac298f06b1 100644 --- a/drivers/clk/qcom/camcc-sm8750.c +++ b/drivers/clk/qcom/camcc-sm8750.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-x1e80100.c b/drivers/clk/qcom/camcc-x1e80100.c index c12994af42cf..2bfd42904a29 100644 --- a/drivers/clk/qcom/camcc-x1e80100.c +++ b/drivers/clk/qcom/camcc-x1e80100.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/camcc-x1p42100.c b/drivers/clk/qcom/camcc-x1p42100.c index c1a61c267919..cfe24bde4652 100644 --- a/drivers/clk/qcom/camcc-x1p42100.c +++ b/drivers/clk/qcom/camcc-x1p42100.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-eliza.c b/drivers/clk/qcom/dispcc-eliza.c index 479f26e0dde2..760881cb1077 100644 --- a/drivers/clk/qcom/dispcc-eliza.c +++ b/drivers/clk/qcom/dispcc-eliza.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-glymur.c b/drivers/clk/qcom/dispcc-glymur.c index c4bb328d432f..32cc5226b4de 100644 --- a/drivers/clk/qcom/dispcc-glymur.c +++ b/drivers/clk/qcom/dispcc-glymur.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-kaanapali.c b/drivers/clk/qcom/dispcc-kaanapali.c index 42912c617c31..f8832482bd7a 100644 --- a/drivers/clk/qcom/dispcc-kaanapali.c +++ b/drivers/clk/qcom/dispcc-kaanapali.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-milos.c b/drivers/clk/qcom/dispcc-milos.c index dfffb6d14b0e..c2f37d3458a0 100644 --- a/drivers/clk/qcom/dispcc-milos.c +++ b/drivers/clk/qcom/dispcc-milos.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-qcm2290.c b/drivers/clk/qcom/dispcc-qcm2290.c index 6d88d067337f..4d6aad280ae1 100644 --- a/drivers/clk/qcom/dispcc-qcm2290.c +++ b/drivers/clk/qcom/dispcc-qcm2290.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-qcs615.c b/drivers/clk/qcom/dispcc-qcs615.c index 637698e6dc2b..6a19f00f6bfa 100644 --- a/drivers/clk/qcom/dispcc-qcs615.c +++ b/drivers/clk/qcom/dispcc-qcs615.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sc7180.c b/drivers/clk/qcom/dispcc-sc7180.c index d7e37fbbe87e..ae98fe4dcfb2 100644 --- a/drivers/clk/qcom/dispcc-sc7180.c +++ b/drivers/clk/qcom/dispcc-sc7180.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sc7280.c b/drivers/clk/qcom/dispcc-sc7280.c index 465dc06c8712..d11265debaf9 100644 --- a/drivers/clk/qcom/dispcc-sc7280.c +++ b/drivers/clk/qcom/dispcc-sc7280.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sc8280xp.c b/drivers/clk/qcom/dispcc-sc8280xp.c index acc927c2142a..96609bd5233f 100644 --- a/drivers/clk/qcom/dispcc-sc8280xp.c +++ b/drivers/clk/qcom/dispcc-sc8280xp.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index 78e43f6d7502..6ad6c4f5d337 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm4450.c b/drivers/clk/qcom/dispcc-sm4450.c index 2fdacc26df69..4a4811db55dd 100644 --- a/drivers/clk/qcom/dispcc-sm4450.c +++ b/drivers/clk/qcom/dispcc-sm4450.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/clk/qcom/dispcc-sm6115.c b/drivers/clk/qcom/dispcc-sm6115.c index 75bd57213079..9a7b8ad646ed 100644 --- a/drivers/clk/qcom/dispcc-sm6115.c +++ b/drivers/clk/qcom/dispcc-sm6115.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm6125.c b/drivers/clk/qcom/dispcc-sm6125.c index 2c67abcfef12..27a73665769c 100644 --- a/drivers/clk/qcom/dispcc-sm6125.c +++ b/drivers/clk/qcom/dispcc-sm6125.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm6350.c b/drivers/clk/qcom/dispcc-sm6350.c index 5b1d8f86515f..16948f435340 100644 --- a/drivers/clk/qcom/dispcc-sm6350.c +++ b/drivers/clk/qcom/dispcc-sm6350.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm6375.c b/drivers/clk/qcom/dispcc-sm6375.c index ec9dbb1f4a7c..167dd369a794 100644 --- a/drivers/clk/qcom/dispcc-sm6375.c +++ b/drivers/clk/qcom/dispcc-sm6375.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm7150.c b/drivers/clk/qcom/dispcc-sm7150.c index ed8e34ffd69b..b9df6153e50f 100644 --- a/drivers/clk/qcom/dispcc-sm7150.c +++ b/drivers/clk/qcom/dispcc-sm7150.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm8250.c b/drivers/clk/qcom/dispcc-sm8250.c index e59cdadd5647..fdc07323f298 100644 --- a/drivers/clk/qcom/dispcc-sm8250.c +++ b/drivers/clk/qcom/dispcc-sm8250.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm8450.c b/drivers/clk/qcom/dispcc-sm8450.c index 2e91332dd92a..3af120e54cdd 100644 --- a/drivers/clk/qcom/dispcc-sm8450.c +++ b/drivers/clk/qcom/dispcc-sm8450.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm8550.c b/drivers/clk/qcom/dispcc-sm8550.c index f27140c649f5..418dcea20f00 100644 --- a/drivers/clk/qcom/dispcc-sm8550.c +++ b/drivers/clk/qcom/dispcc-sm8550.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-sm8750.c b/drivers/clk/qcom/dispcc-sm8750.c index ca09da111a50..18e86b80e581 100644 --- a/drivers/clk/qcom/dispcc-sm8750.c +++ b/drivers/clk/qcom/dispcc-sm8750.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc-x1e80100.c b/drivers/clk/qcom/dispcc-x1e80100.c index 1d7c569dc082..795279609c0b 100644 --- a/drivers/clk/qcom/dispcc-x1e80100.c +++ b/drivers/clk/qcom/dispcc-x1e80100.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc0-sa8775p.c b/drivers/clk/qcom/dispcc0-sa8775p.c index b248fa970587..0e976442834a 100644 --- a/drivers/clk/qcom/dispcc0-sa8775p.c +++ b/drivers/clk/qcom/dispcc0-sa8775p.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/dispcc1-sa8775p.c b/drivers/clk/qcom/dispcc1-sa8775p.c index 9882edbb79f9..58008c1afc76 100644 --- a/drivers/clk/qcom/dispcc1-sa8775p.c +++ b/drivers/clk/qcom/dispcc1-sa8775p.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/ecpricc-qdu1000.c b/drivers/clk/qcom/ecpricc-qdu1000.c index c2a16616ed64..5a33aa1615b8 100644 --- a/drivers/clk/qcom/ecpricc-qdu1000.c +++ b/drivers/clk/qcom/ecpricc-qdu1000.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-eliza.c b/drivers/clk/qcom/gcc-eliza.c index 24c3aae0810f..3e26c7a1e5b5 100644 --- a/drivers/clk/qcom/gcc-eliza.c +++ b/drivers/clk/qcom/gcc-eliza.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-glymur.c b/drivers/clk/qcom/gcc-glymur.c index 2736465efdea..f4ede4a3a1c0 100644 --- a/drivers/clk/qcom/gcc-glymur.c +++ b/drivers/clk/qcom/gcc-glymur.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-hawi.c b/drivers/clk/qcom/gcc-hawi.c index 6dd07c772c29..018411e4f402 100644 --- a/drivers/clk/qcom/gcc-hawi.c +++ b/drivers/clk/qcom/gcc-hawi.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-ipq5018.c b/drivers/clk/qcom/gcc-ipq5018.c index 64792cda0620..594dae3bac4c 100644 --- a/drivers/clk/qcom/gcc-ipq5018.c +++ b/drivers/clk/qcom/gcc-ipq5018.c @@ -3,7 +3,6 @@ * Copyright (c) 2023, The Linux Foundation. All rights reserved. */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-ipq5332.c b/drivers/clk/qcom/gcc-ipq5332.c index 9246e97d785a..ecd9ebeed754 100644 --- a/drivers/clk/qcom/gcc-ipq5332.c +++ b/drivers/clk/qcom/gcc-ipq5332.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-kaanapali.c b/drivers/clk/qcom/gcc-kaanapali.c index 6e628b51f38c..842c1a70c691 100644 --- a/drivers/clk/qcom/gcc-kaanapali.c +++ b/drivers/clk/qcom/gcc-kaanapali.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-milos.c b/drivers/clk/qcom/gcc-milos.c index 67d0eee8ef35..4219af2879d9 100644 --- a/drivers/clk/qcom/gcc-milos.c +++ b/drivers/clk/qcom/gcc-milos.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-nord.c b/drivers/clk/qcom/gcc-nord.c index 8a6e429f2640..7c7c2171ac96 100644 --- a/drivers/clk/qcom/gcc-nord.c +++ b/drivers/clk/qcom/gcc-nord.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-qcs615.c b/drivers/clk/qcom/gcc-qcs615.c index 5b3b8dd4f114..57f8c80c6f32 100644 --- a/drivers/clk/qcom/gcc-qcs615.c +++ b/drivers/clk/qcom/gcc-qcs615.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-qcs8300.c b/drivers/clk/qcom/gcc-qcs8300.c index 80831c7dea3b..07218d9c96a7 100644 --- a/drivers/clk/qcom/gcc-qcs8300.c +++ b/drivers/clk/qcom/gcc-qcs8300.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-sa8775p.c b/drivers/clk/qcom/gcc-sa8775p.c index e7425e82c54f..dca316decd0e 100644 --- a/drivers/clk/qcom/gcc-sa8775p.c +++ b/drivers/clk/qcom/gcc-sa8775p.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-sdx75.c b/drivers/clk/qcom/gcc-sdx75.c index 1f3cd58483a2..6712e76f875c 100644 --- a/drivers/clk/qcom/gcc-sdx75.c +++ b/drivers/clk/qcom/gcc-sdx75.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-sm4450.c b/drivers/clk/qcom/gcc-sm4450.c index 023d840e9f4e..30fc7af09930 100644 --- a/drivers/clk/qcom/gcc-sm4450.c +++ b/drivers/clk/qcom/gcc-sm4450.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-sm7150.c b/drivers/clk/qcom/gcc-sm7150.c index 7eabaf0e1b57..dcb5d82a1a31 100644 --- a/drivers/clk/qcom/gcc-sm7150.c +++ b/drivers/clk/qcom/gcc-sm7150.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-sm8650.c b/drivers/clk/qcom/gcc-sm8650.c index 2dd6444ce036..f7e2d7ec60c9 100644 --- a/drivers/clk/qcom/gcc-sm8650.c +++ b/drivers/clk/qcom/gcc-sm8650.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-sm8750.c b/drivers/clk/qcom/gcc-sm8750.c index db81569dd4b1..6cfe90122268 100644 --- a/drivers/clk/qcom/gcc-sm8750.c +++ b/drivers/clk/qcom/gcc-sm8750.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gcc-x1e80100.c b/drivers/clk/qcom/gcc-x1e80100.c index 73a2a5112623..8c146d62c077 100644 --- a/drivers/clk/qcom/gcc-x1e80100.c +++ b/drivers/clk/qcom/gcc-x1e80100.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-glymur.c b/drivers/clk/qcom/gpucc-glymur.c index 54cc3127718a..001b2454786a 100644 --- a/drivers/clk/qcom/gpucc-glymur.c +++ b/drivers/clk/qcom/gpucc-glymur.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-kaanapali.c b/drivers/clk/qcom/gpucc-kaanapali.c index 7f6013b348ad..ae5563e516f6 100644 --- a/drivers/clk/qcom/gpucc-kaanapali.c +++ b/drivers/clk/qcom/gpucc-kaanapali.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-milos.c b/drivers/clk/qcom/gpucc-milos.c index 1448d95cb1dc..6129f9aa5802 100644 --- a/drivers/clk/qcom/gpucc-milos.c +++ b/drivers/clk/qcom/gpucc-milos.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-msm8998.c b/drivers/clk/qcom/gpucc-msm8998.c index 7fce70503141..066793e47f79 100644 --- a/drivers/clk/qcom/gpucc-msm8998.c +++ b/drivers/clk/qcom/gpucc-msm8998.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-qcm2290.c b/drivers/clk/qcom/gpucc-qcm2290.c index dc369dff882e..66dea9d2a0e5 100644 --- a/drivers/clk/qcom/gpucc-qcm2290.c +++ b/drivers/clk/qcom/gpucc-qcm2290.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-qcs615.c b/drivers/clk/qcom/gpucc-qcs615.c index 91919cdb75ae..5032d0900c69 100644 --- a/drivers/clk/qcom/gpucc-qcs615.c +++ b/drivers/clk/qcom/gpucc-qcs615.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sa8775p.c b/drivers/clk/qcom/gpucc-sa8775p.c index 25dcc5912f99..759827e84c56 100644 --- a/drivers/clk/qcom/gpucc-sa8775p.c +++ b/drivers/clk/qcom/gpucc-sa8775p.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sar2130p.c b/drivers/clk/qcom/gpucc-sar2130p.c index c2903179ac85..dd72b2a48c42 100644 --- a/drivers/clk/qcom/gpucc-sar2130p.c +++ b/drivers/clk/qcom/gpucc-sar2130p.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sc7180.c b/drivers/clk/qcom/gpucc-sc7180.c index 97287488e05a..b14a53db55fd 100644 --- a/drivers/clk/qcom/gpucc-sc7180.c +++ b/drivers/clk/qcom/gpucc-sc7180.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sc7280.c b/drivers/clk/qcom/gpucc-sc7280.c index f81289fa719d..bd699a624517 100644 --- a/drivers/clk/qcom/gpucc-sc7280.c +++ b/drivers/clk/qcom/gpucc-sc7280.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sc8280xp.c b/drivers/clk/qcom/gpucc-sc8280xp.c index 2645612f1cac..5dd90b854afb 100644 --- a/drivers/clk/qcom/gpucc-sc8280xp.c +++ b/drivers/clk/qcom/gpucc-sc8280xp.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sdm660.c b/drivers/clk/qcom/gpucc-sdm660.c index 28db307b6717..6d37b3d8d1a4 100644 --- a/drivers/clk/qcom/gpucc-sdm660.c +++ b/drivers/clk/qcom/gpucc-sdm660.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c index 0d63b110a1fb..ef26690cf504 100644 --- a/drivers/clk/qcom/gpucc-sdm845.c +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm4450.c b/drivers/clk/qcom/gpucc-sm4450.c index 34c7ba0c7d55..808b1eaa59d1 100644 --- a/drivers/clk/qcom/gpucc-sm4450.c +++ b/drivers/clk/qcom/gpucc-sm4450.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/clk/qcom/gpucc-sm6115.c b/drivers/clk/qcom/gpucc-sm6115.c index d43c86cf73a5..a075fa395643 100644 --- a/drivers/clk/qcom/gpucc-sm6115.c +++ b/drivers/clk/qcom/gpucc-sm6115.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm6125.c b/drivers/clk/qcom/gpucc-sm6125.c index ed6a6e505801..ecaabd58bc0e 100644 --- a/drivers/clk/qcom/gpucc-sm6125.c +++ b/drivers/clk/qcom/gpucc-sm6125.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm6350.c b/drivers/clk/qcom/gpucc-sm6350.c index efbee1518dd3..d27e4ad7be51 100644 --- a/drivers/clk/qcom/gpucc-sm6350.c +++ b/drivers/clk/qcom/gpucc-sm6350.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm6375.c b/drivers/clk/qcom/gpucc-sm6375.c index 41f59024143e..eebbc6de28e5 100644 --- a/drivers/clk/qcom/gpucc-sm6375.c +++ b/drivers/clk/qcom/gpucc-sm6375.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm8150.c b/drivers/clk/qcom/gpucc-sm8150.c index 5701031c17f3..8e25b4fc6e52 100644 --- a/drivers/clk/qcom/gpucc-sm8150.c +++ b/drivers/clk/qcom/gpucc-sm8150.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm8250.c b/drivers/clk/qcom/gpucc-sm8250.c index eee3208640cd..cc77fd03d11f 100644 --- a/drivers/clk/qcom/gpucc-sm8250.c +++ b/drivers/clk/qcom/gpucc-sm8250.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm8350.c b/drivers/clk/qcom/gpucc-sm8350.c index 4025dab0a1ca..6d2660bdd825 100644 --- a/drivers/clk/qcom/gpucc-sm8350.c +++ b/drivers/clk/qcom/gpucc-sm8350.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm8450.c b/drivers/clk/qcom/gpucc-sm8450.c index 059df72deaa1..49c4879e74cf 100644 --- a/drivers/clk/qcom/gpucc-sm8450.c +++ b/drivers/clk/qcom/gpucc-sm8450.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm8550.c b/drivers/clk/qcom/gpucc-sm8550.c index 7486edf56160..53614e980b26 100644 --- a/drivers/clk/qcom/gpucc-sm8550.c +++ b/drivers/clk/qcom/gpucc-sm8550.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm8650.c b/drivers/clk/qcom/gpucc-sm8650.c index f15aeecc512d..a84fa35bc2ba 100644 --- a/drivers/clk/qcom/gpucc-sm8650.c +++ b/drivers/clk/qcom/gpucc-sm8650.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-sm8750.c b/drivers/clk/qcom/gpucc-sm8750.c index 1466bd36403f..728597d0f82d 100644 --- a/drivers/clk/qcom/gpucc-sm8750.c +++ b/drivers/clk/qcom/gpucc-sm8750.c @@ -3,7 +3,6 @@ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-x1e80100.c b/drivers/clk/qcom/gpucc-x1e80100.c index 2eec20dd0254..f9161dbaedd7 100644 --- a/drivers/clk/qcom/gpucc-x1e80100.c +++ b/drivers/clk/qcom/gpucc-x1e80100.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gpucc-x1p42100.c b/drivers/clk/qcom/gpucc-x1p42100.c index 4031d3ff560a..cfc34e0fd290 100644 --- a/drivers/clk/qcom/gpucc-x1p42100.c +++ b/drivers/clk/qcom/gpucc-x1p42100.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/gxclkctl-kaanapali.c b/drivers/clk/qcom/gxclkctl-kaanapali.c index 7b0af0ba1e68..10c1a8976c56 100644 --- a/drivers/clk/qcom/gxclkctl-kaanapali.c +++ b/drivers/clk/qcom/gxclkctl-kaanapali.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/ipq-cmn-pll.c b/drivers/clk/qcom/ipq-cmn-pll.c index 441e88101ea3..dafe8c1738df 100644 --- a/drivers/clk/qcom/ipq-cmn-pll.c +++ b/drivers/clk/qcom/ipq-cmn-pll.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/lpasscc-sc8280xp.c b/drivers/clk/qcom/lpasscc-sc8280xp.c index ff839788c40e..32769281b220 100644 --- a/drivers/clk/qcom/lpasscc-sc8280xp.c +++ b/drivers/clk/qcom/lpasscc-sc8280xp.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/lpasscc-sm6115.c b/drivers/clk/qcom/lpasscc-sm6115.c index ac6d219233b4..226dc02fc42d 100644 --- a/drivers/clk/qcom/lpasscc-sm6115.c +++ b/drivers/clk/qcom/lpasscc-sm6115.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index 2d334977d783..3affa525b875 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/qcom/mmcc-msm8960.c b/drivers/clk/qcom/mmcc-msm8960.c index cd3c9f8455e5..a23440e13b71 100644 --- a/drivers/clk/qcom/mmcc-msm8960.c +++ b/drivers/clk/qcom/mmcc-msm8960.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/mmcc-msm8974.c b/drivers/clk/qcom/mmcc-msm8974.c index 12bbc49c87af..f2e802cf6afc 100644 --- a/drivers/clk/qcom/mmcc-msm8974.c +++ b/drivers/clk/qcom/mmcc-msm8974.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/mmcc-msm8994.c b/drivers/clk/qcom/mmcc-msm8994.c index 7c0b959a4aa2..0a273630e852 100644 --- a/drivers/clk/qcom/mmcc-msm8994.c +++ b/drivers/clk/qcom/mmcc-msm8994.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index 7d67c6f73fe1..3426e3dde924 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/mmcc-msm8998.c b/drivers/clk/qcom/mmcc-msm8998.c index e2f198213b21..5c37be700fa7 100644 --- a/drivers/clk/qcom/mmcc-msm8998.c +++ b/drivers/clk/qcom/mmcc-msm8998.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/mmcc-sdm660.c b/drivers/clk/qcom/mmcc-sdm660.c index dbd3f561dc6d..200f986de965 100644 --- a/drivers/clk/qcom/mmcc-sdm660.c +++ b/drivers/clk/qcom/mmcc-sdm660.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/negcc-nord.c b/drivers/clk/qcom/negcc-nord.c index 2e653ef0fe0e..355850a875ac 100644 --- a/drivers/clk/qcom/negcc-nord.c +++ b/drivers/clk/qcom/negcc-nord.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/nwgcc-nord.c b/drivers/clk/qcom/nwgcc-nord.c index 961cae47ff7c..e061c0623e9a 100644 --- a/drivers/clk/qcom/nwgcc-nord.c +++ b/drivers/clk/qcom/nwgcc-nord.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/segcc-nord.c b/drivers/clk/qcom/segcc-nord.c index c82a56d97154..51d7f83e21b6 100644 --- a/drivers/clk/qcom/segcc-nord.c +++ b/drivers/clk/qcom/segcc-nord.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/tcsrcc-eliza.c b/drivers/clk/qcom/tcsrcc-eliza.c index 5a47a4c77cb5..127d1f0a1442 100644 --- a/drivers/clk/qcom/tcsrcc-eliza.c +++ b/drivers/clk/qcom/tcsrcc-eliza.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/tcsrcc-glymur.c b/drivers/clk/qcom/tcsrcc-glymur.c index 9c0edebcdbb1..b44fccb795c6 100644 --- a/drivers/clk/qcom/tcsrcc-glymur.c +++ b/drivers/clk/qcom/tcsrcc-glymur.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/tcsrcc-hawi.c b/drivers/clk/qcom/tcsrcc-hawi.c index c942b0c8e09f..808bdba6e432 100644 --- a/drivers/clk/qcom/tcsrcc-hawi.c +++ b/drivers/clk/qcom/tcsrcc-hawi.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/tcsrcc-nord.c b/drivers/clk/qcom/tcsrcc-nord.c index ed0f4909158f..cbe59e8a5b01 100644 --- a/drivers/clk/qcom/tcsrcc-nord.c +++ b/drivers/clk/qcom/tcsrcc-nord.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/tcsrcc-sm8650.c b/drivers/clk/qcom/tcsrcc-sm8650.c index 3685dcde9a4b..651e28067954 100644 --- a/drivers/clk/qcom/tcsrcc-sm8650.c +++ b/drivers/clk/qcom/tcsrcc-sm8650.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/tcsrcc-sm8750.c b/drivers/clk/qcom/tcsrcc-sm8750.c index 46af98760197..9fe840a448bf 100644 --- a/drivers/clk/qcom/tcsrcc-sm8750.c +++ b/drivers/clk/qcom/tcsrcc-sm8750.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/tcsrcc-x1e80100.c b/drivers/clk/qcom/tcsrcc-x1e80100.c index a367e1f55622..0b05c27b619b 100644 --- a/drivers/clk/qcom/tcsrcc-x1e80100.c +++ b/drivers/clk/qcom/tcsrcc-x1e80100.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-glymur.c b/drivers/clk/qcom/videocc-glymur.c index bbf13f4ba82d..18313a65e78d 100644 --- a/drivers/clk/qcom/videocc-glymur.c +++ b/drivers/clk/qcom/videocc-glymur.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-kaanapali.c b/drivers/clk/qcom/videocc-kaanapali.c index b29e3da465e5..1f4ac18f86fa 100644 --- a/drivers/clk/qcom/videocc-kaanapali.c +++ b/drivers/clk/qcom/videocc-kaanapali.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-milos.c b/drivers/clk/qcom/videocc-milos.c index 3cce34e8c71a..386f2e1255d4 100644 --- a/drivers/clk/qcom/videocc-milos.c +++ b/drivers/clk/qcom/videocc-milos.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-qcs615.c b/drivers/clk/qcom/videocc-qcs615.c index 3203cb938ad1..3bfea382c3ac 100644 --- a/drivers/clk/qcom/videocc-qcs615.c +++ b/drivers/clk/qcom/videocc-qcs615.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-sa8775p.c b/drivers/clk/qcom/videocc-sa8775p.c index 2476201dcd20..65a2d5bafea6 100644 --- a/drivers/clk/qcom/videocc-sa8775p.c +++ b/drivers/clk/qcom/videocc-sa8775p.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-sm7150.c b/drivers/clk/qcom/videocc-sm7150.c index b6912560ef9b..8d2e00799f96 100644 --- a/drivers/clk/qcom/videocc-sm7150.c +++ b/drivers/clk/qcom/videocc-sm7150.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-sm8450.c b/drivers/clk/qcom/videocc-sm8450.c index 18b191f598b5..887044aa3b24 100644 --- a/drivers/clk/qcom/videocc-sm8450.c +++ b/drivers/clk/qcom/videocc-sm8450.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-sm8550.c b/drivers/clk/qcom/videocc-sm8550.c index 4e35964f0803..c2f11489a222 100644 --- a/drivers/clk/qcom/videocc-sm8550.c +++ b/drivers/clk/qcom/videocc-sm8550.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-sm8750.c b/drivers/clk/qcom/videocc-sm8750.c index e9414390a3cc..b62271a7dac6 100644 --- a/drivers/clk/qcom/videocc-sm8750.c +++ b/drivers/clk/qcom/videocc-sm8750.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/qcom/videocc-x1p42100.c b/drivers/clk/qcom/videocc-x1p42100.c index 2bb40ac6fcc5..503c03210ec8 100644 --- a/drivers/clk/qcom/videocc-x1p42100.c +++ b/drivers/clk/qcom/videocc-x1p42100.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/renesas/clk-vbattb.c b/drivers/clk/renesas/clk-vbattb.c index 2a961775b1d8..bd97a68bed1b 100644 --- a/drivers/clk/renesas/clk-vbattb.c +++ b/drivers/clk/renesas/clk-vbattb.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 5b84cbee030b..b6dab92cb220 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c index 51c9e19e1575..975b705d3a2b 100644 --- a/drivers/clk/renesas/rzg2l-cpg.c +++ b/drivers/clk/renesas/rzg2l-cpg.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/renesas/rzv2h-cpg.c b/drivers/clk/renesas/rzv2h-cpg.c index e271c04cee34..5bdfdc415bb6 100644 --- a/drivers/clk/renesas/rzv2h-cpg.c +++ b/drivers/clk/renesas/rzv2h-cpg.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 0f5ae3e8d000..e11ac67819ef 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index 5b21025338bd..5f64d93b2fac 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos2200.c b/drivers/clk/samsung/clk-exynos2200.c index eab9f5eecfa3..6a6ac34f90b9 100644 --- a/drivers/clk/samsung/clk-exynos2200.c +++ b/drivers/clk/samsung/clk-exynos2200.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c index 84564ec4c8ec..32d12658e1a9 100644 --- a/drivers/clk/samsung/clk-exynos3250.c +++ b/drivers/clk/samsung/clk-exynos3250.c @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 246bd28bac2d..eaa8667a6ad5 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c index 772bc18a1e68..0e66f94ceab5 100644 --- a/drivers/clk/samsung/clk-exynos4412-isp.c +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c index 03bbde76e3ce..373129847301 100644 --- a/drivers/clk/samsung/clk-exynos5-subcmu.c +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -5,7 +5,6 @@ // Common Clock Framework support for Exynos5 power-domain dependent clocks #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index f97f30b29be7..802300c945a9 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 1982e0751cee..400a5c59815c 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 4b2a861e7d57..6bc64e446351 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk-exynos7870.c b/drivers/clk/samsung/clk-exynos7870.c index b3bcf3a1d0b7..fd39ec77804a 100644 --- a/drivers/clk/samsung/clk-exynos7870.c +++ b/drivers/clk/samsung/clk-exynos7870.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos7885.c b/drivers/clk/samsung/clk-exynos7885.c index ba7cf79bc300..17c2a4fc1a55 100644 --- a/drivers/clk/samsung/clk-exynos7885.c +++ b/drivers/clk/samsung/clk-exynos7885.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos850.c b/drivers/clk/samsung/clk-exynos850.c index b143a42293f5..ebcdde93bd46 100644 --- a/drivers/clk/samsung/clk-exynos850.c +++ b/drivers/clk/samsung/clk-exynos850.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos8895.c b/drivers/clk/samsung/clk-exynos8895.c index e6980a8f026f..259481c4276e 100644 --- a/drivers/clk/samsung/clk-exynos8895.c +++ b/drivers/clk/samsung/clk-exynos8895.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynos990.c b/drivers/clk/samsung/clk-exynos990.c index 4385c3b76dd6..7a27557e6713 100644 --- a/drivers/clk/samsung/clk-exynos990.c +++ b/drivers/clk/samsung/clk-exynos990.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynosautov9.c b/drivers/clk/samsung/clk-exynosautov9.c index e4d7c7b96aa8..507c92e09ccf 100644 --- a/drivers/clk/samsung/clk-exynosautov9.c +++ b/drivers/clk/samsung/clk-exynosautov9.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-exynosautov920.c b/drivers/clk/samsung/clk-exynosautov920.c index 04cd40c71d13..a938f3cc7b57 100644 --- a/drivers/clk/samsung/clk-exynosautov920.c +++ b/drivers/clk/samsung/clk-exynosautov920.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-fsd.c b/drivers/clk/samsung/clk-fsd.c index 4124d65e3d18..0a0bf1d62a04 100644 --- a/drivers/clk/samsung/clk-fsd.c +++ b/drivers/clk/samsung/clk-fsd.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/samsung/clk-gs101.c b/drivers/clk/samsung/clk-gs101.c index b44bb31f38b3..9a42b44f4f26 100644 --- a/drivers/clk/samsung/clk-gs101.c +++ b/drivers/clk/samsung/clk-gs101.c @@ -7,7 +7,6 @@ */ #include -#include #include #include diff --git a/drivers/clk/samsung/clk-s5pv210-audss.c b/drivers/clk/samsung/clk-s5pv210-audss.c index c9fcb23de183..1b83fdd496e9 100644 --- a/drivers/clk/samsung/clk-s5pv210-audss.c +++ b/drivers/clk/samsung/clk-s5pv210-audss.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 91e5cdbc79d7..7f1bc3e31442 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/sprd/ums512-clk.c b/drivers/clk/sprd/ums512-clk.c index f763d83de9ee..fc17b74b869f 100644 --- a/drivers/clk/sprd/ums512-clk.c +++ b/drivers/clk/sprd/ums512-clk.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/clk/starfive/clk-starfive-jh7100-audio.c b/drivers/clk/starfive/clk-starfive-jh7100-audio.c index 7de23f6749aa..de1cf717e391 100644 --- a/drivers/clk/starfive/clk-starfive-jh7100-audio.c +++ b/drivers/clk/starfive/clk-starfive-jh7100-audio.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/starfive/clk-starfive-jh7100.c b/drivers/clk/starfive/clk-starfive-jh7100.c index 03f6f26a15d8..761e46ed0ffd 100644 --- a/drivers/clk/starfive/clk-starfive-jh7100.c +++ b/drivers/clk/starfive/clk-starfive-jh7100.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/clk/tegra/clk-device.c b/drivers/clk/tegra/clk-device.c index e0531f6dcfb0..a75f71462df2 100644 --- a/drivers/clk/tegra/clk-device.c +++ b/drivers/clk/tegra/clk-device.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include diff --git a/drivers/clk/xilinx/xlnx_vcu.c b/drivers/clk/xilinx/xlnx_vcu.c index 02699bc0f82c..f14bda375e35 100644 --- a/drivers/clk/xilinx/xlnx_vcu.c +++ b/drivers/clk/xilinx/xlnx_vcu.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/counter/interrupt-cnt.c b/drivers/counter/interrupt-cnt.c index cd475382ab6a..694292051aa5 100644 --- a/drivers/counter/interrupt-cnt.c +++ b/drivers/counter/interrupt-cnt.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c index b249c8647639..cbbb1232becd 100644 --- a/drivers/counter/stm32-lptimer-cnt.c +++ b/drivers/counter/stm32-lptimer-cnt.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 3d3384cbea87..a3d8f7a5874e 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/counter/ti-ecap-capture.c b/drivers/counter/ti-ecap-capture.c index 3586a7ab9887..f69b6920463f 100644 --- a/drivers/counter/ti-ecap-capture.c +++ b/drivers/counter/ti-ecap-capture.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c index d21c157e531a..d9302ec21163 100644 --- a/drivers/counter/ti-eqep.c +++ b/drivers/counter/ti-eqep.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/cpufreq/amd_freq_sensitivity.c b/drivers/cpufreq/amd_freq_sensitivity.c index 739d54dc9f2b..e0cd3a9a5f00 100644 --- a/drivers/cpufreq/amd_freq_sensitivity.c +++ b/drivers/cpufreq/amd_freq_sensitivity.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index 1ec54fc4c2ba..79b6b8411b8d 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index b393689400b4..f79d7c456546 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 8e3b8efa8109..66323ac63406 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 643e507f9c02..3c0eacacfc87 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 2da0894f31fd..46bcef044606 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/img-hash.c b/drivers/crypto/img-hash.c index c0467185ee42..0f19dcc2f388 100644 --- a/drivers/crypto/img-hash.c +++ b/drivers/crypto/img-hash.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c index 48281d882260..87b67060c77b 100644 --- a/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c +++ b/drivers/crypto/intel/keembay/keembay-ocs-hcu-core.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index b966f3365b7d..ac74f69914d6 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/starfive/jh7110-cryp.c b/drivers/crypto/starfive/jh7110-cryp.c index e19cd7945968..842f76b0f114 100644 --- a/drivers/crypto/starfive/jh7110-cryp.c +++ b/drivers/crypto/starfive/jh7110-cryp.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 584508963241..3a3fd21d2c4d 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/crypto/tegra/tegra-se-main.c b/drivers/crypto/tegra/tegra-se-main.c index d2f518ef9a10..497ff270489c 100644 --- a/drivers/crypto/tegra/tegra-se-main.c +++ b/drivers/crypto/tegra/tegra-se-main.c @@ -8,7 +8,6 @@ #include #include #include -#include #include diff --git a/drivers/crypto/ti/dthev2-common.c b/drivers/crypto/ti/dthev2-common.c index a2ad79bec105..ba6cde75d361 100644 --- a/drivers/crypto/ti/dthev2-common.c +++ b/drivers/crypto/ti/dthev2-common.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/crypto/xilinx/zynqmp-aes-gcm.c b/drivers/crypto/xilinx/zynqmp-aes-gcm.c index 2421bf30556d..d54c268dfe34 100644 --- a/drivers/crypto/xilinx/zynqmp-aes-gcm.c +++ b/drivers/crypto/xilinx/zynqmp-aes-gcm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/devfreq/hisi_uncore_freq.c b/drivers/devfreq/hisi_uncore_freq.c index 4d00d813c8ac..bef718d6ae35 100644 --- a/drivers/devfreq/hisi_uncore_freq.c +++ b/drivers/devfreq/hisi_uncore_freq.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/devfreq/imx8m-ddrc.c b/drivers/devfreq/imx8m-ddrc.c index e1348490c8aa..52beeb5b7d65 100644 --- a/drivers/devfreq/imx8m-ddrc.c +++ b/drivers/devfreq/imx8m-ddrc.c @@ -3,7 +3,6 @@ * Copyright 2019 NXP */ -#include #include #include #include diff --git a/drivers/dma-buf/dma-fence-unwrap.c b/drivers/dma-buf/dma-fence-unwrap.c index 65e87d263c3a..120fe0c2a75a 100644 --- a/drivers/dma-buf/dma-fence-unwrap.c +++ b/drivers/dma-buf/dma-fence-unwrap.c @@ -97,6 +97,9 @@ size_t dma_fence_dedup_array(struct dma_fence **fences, size_t num_fences) { size_t i, j; + if (!num_fences) + return 0; + sort(fences, num_fences, sizeof(*fences), fence_cmp, NULL); /* diff --git a/drivers/dma-buf/dma-fence.c b/drivers/dma-buf/dma-fence.c index 0ec81a568bbd..05090fb0fd5a 100644 --- a/drivers/dma-buf/dma-fence.c +++ b/drivers/dma-buf/dma-fence.c @@ -1170,7 +1170,7 @@ const char __rcu *dma_fence_driver_name(struct dma_fence *fence) /* RCU protection is required for safe access to returned string */ ops = rcu_dereference(fence->ops); - if (!dma_fence_test_signaled_flag(fence)) + if (ops) return (const char __rcu *)ops->get_driver_name(fence); else return (const char __rcu *)"detached-driver"; @@ -1203,8 +1203,8 @@ const char __rcu *dma_fence_timeline_name(struct dma_fence *fence) /* RCU protection is required for safe access to returned string */ ops = rcu_dereference(fence->ops); - if (!dma_fence_test_signaled_flag(fence)) - return (const char __rcu *)ops->get_driver_name(fence); + if (ops) + return (const char __rcu *)ops->get_timeline_name(fence); else return (const char __rcu *)"signaled-timeline"; } diff --git a/drivers/dma/amd/qdma/qdma.c b/drivers/dma/amd/qdma/qdma.c index f5a02c6ed348..3e61e8c4356a 100644 --- a/drivers/dma/amd/qdma/qdma.c +++ b/drivers/dma/amd/qdma/qdma.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c index a3395cfcf5dd..311e55a97ba9 100644 --- a/drivers/dma/ep93xx_dma.c +++ b/drivers/dma/ep93xx_dma.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 7a7f302a9699..c939635be21d 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/sf-pdma/sf-pdma.c b/drivers/dma/sf-pdma/sf-pdma.c index b3cba11b6203..6f79cc28703e 100644 --- a/drivers/dma/sf-pdma/sf-pdma.c +++ b/drivers/dma/sf-pdma/sf-pdma.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index f64624ea44ad..fa1173e49900 100644 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index 90a22a730cc9..8d4a5d14e8db 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -20,7 +20,6 @@ * user interrupt wires that generate interrupts to the host. */ -#include #include #include #include diff --git a/drivers/dpll/zl3073x/dpll.c b/drivers/dpll/zl3073x/dpll.c index 5e58ded5734d..4ab045e85a89 100644 --- a/drivers/dpll/zl3073x/dpll.c +++ b/drivers/dpll/zl3073x/dpll.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index e4eaec0aa81d..b27dff96aeb6 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 277f1c6bd522..7bb13f85ce57 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/edac/pnd2_edac.c b/drivers/edac/pnd2_edac.c index af14c8a3279f..ea208c637113 100644 --- a/drivers/edac/pnd2_edac.c +++ b/drivers/edac/pnd2_edac.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 35eb7a2038ab..6e248855a549 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/extcon/extcon-intel-cht-wc.c b/drivers/extcon/extcon-intel-cht-wc.c index 8131a3d7d562..99a9dfc62e2b 100644 --- a/drivers/extcon/extcon-intel-cht-wc.c +++ b/drivers/extcon/extcon-intel-cht-wc.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/extcon/extcon-intel-mrfld.c b/drivers/extcon/extcon-intel-mrfld.c index 9219f4328d70..7246d704fa3d 100644 --- a/drivers/extcon/extcon-intel-mrfld.c +++ b/drivers/extcon/extcon-intel-mrfld.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/extcon/extcon-max14526.c b/drivers/extcon/extcon-max14526.c index 3750a5c20612..bf8997827475 100644 --- a/drivers/extcon/extcon-max14526.c +++ b/drivers/extcon/extcon-max14526.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c index b2ee4ff8b04d..d687d178aff1 100644 --- a/drivers/extcon/extcon-max3355.c +++ b/drivers/extcon/extcon-max3355.c @@ -10,7 +10,6 @@ #include #include #include -#include #include struct max3355_data { diff --git a/drivers/extcon/extcon-qcom-spmi-misc.c b/drivers/extcon/extcon-qcom-spmi-misc.c index afaba5685c3d..3c522c9c92f3 100644 --- a/drivers/extcon/extcon-qcom-spmi-misc.c +++ b/drivers/extcon/extcon-qcom-spmi-misc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/extcon/extcon-usb-gpio.c b/drivers/extcon/extcon-usb-gpio.c index 5e8ad21ad206..e35fd1f699a6 100644 --- a/drivers/extcon/extcon-usb-gpio.c +++ b/drivers/extcon/extcon-usb-gpio.c @@ -17,7 +17,6 @@ #include #include #include -#include #define USB_GPIO_DEBOUNCE_MS 20 /* ms */ diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index c0f17da27a22..cbac66916240 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c index 82b3b6d9ed2d..e5361f4f8bbd 100644 --- a/drivers/firewire/net.c +++ b/drivers/firewire/net.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 021b8f698e34..31ee94ecb892 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/firmware/google/cbmem.c b/drivers/firmware/google/cbmem.c index 3397bacdfdbe..4d20477ed9b2 100644 --- a/drivers/firmware/google/cbmem.c +++ b/drivers/firmware/google/cbmem.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/firmware/google/coreboot_table.c b/drivers/firmware/google/coreboot_table.c index 83f7eedf0b3f..e63933ff6747 100644 --- a/drivers/firmware/google/coreboot_table.c +++ b/drivers/firmware/google/coreboot_table.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/firmware/google/framebuffer-coreboot.c b/drivers/firmware/google/framebuffer-coreboot.c index 2c63a9bd0dcb..1a6d4ac6db31 100644 --- a/drivers/firmware/google/framebuffer-coreboot.c +++ b/drivers/firmware/google/framebuffer-coreboot.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/firmware/google/memconsole-coreboot.c b/drivers/firmware/google/memconsole-coreboot.c index 4aa9b1cad3c3..75e372732c67 100644 --- a/drivers/firmware/google/memconsole-coreboot.c +++ b/drivers/firmware/google/memconsole-coreboot.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "memconsole.h" diff --git a/drivers/firmware/google/vpd.c b/drivers/firmware/google/vpd.c index dd058291250b..fbb5a8d7cd0d 100644 --- a/drivers/firmware/google/vpd.c +++ b/drivers/firmware/google/vpd.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/firmware/qemu_fw_cfg.c b/drivers/firmware/qemu_fw_cfg.c index 0c51a9df589f..891a7b21e4b4 100644 --- a/drivers/firmware/qemu_fw_cfg.c +++ b/drivers/firmware/qemu_fw_cfg.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c index 594693ff786e..c24c976117c8 100644 --- a/drivers/fpga/altera-freeze-bridge.c +++ b/drivers/fpga/altera-freeze-bridge.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/fpga/altera-pr-ip-core-plat.c b/drivers/fpga/altera-pr-ip-core-plat.c index 9dc263930007..8cde34d6f153 100644 --- a/drivers/fpga/altera-pr-ip-core-plat.c +++ b/drivers/fpga/altera-pr-ip-core-plat.c @@ -9,7 +9,6 @@ */ #include #include -#include #include static int alt_pr_platform_probe(struct platform_device *pdev) diff --git a/drivers/fpga/ice40-spi.c b/drivers/fpga/ice40-spi.c index 62c30266130d..f72d38d9fe4f 100644 --- a/drivers/fpga/ice40-spi.c +++ b/drivers/fpga/ice40-spi.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/fpga/intel-m10-bmc-sec-update.c b/drivers/fpga/intel-m10-bmc-sec-update.c index b15dab6a39a3..7d23d914df3f 100644 --- a/drivers/fpga/intel-m10-bmc-sec-update.c +++ b/drivers/fpga/intel-m10-bmc-sec-update.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/fpga/lattice-sysconfig-spi.c b/drivers/fpga/lattice-sysconfig-spi.c index 5d195602b261..b39c62f56864 100644 --- a/drivers/fpga/lattice-sysconfig-spi.c +++ b/drivers/fpga/lattice-sysconfig-spi.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c index 2cd87e7e913f..d0cbb5fdfe3a 100644 --- a/drivers/fpga/xilinx-selectmap.c +++ b/drivers/fpga/xilinx-selectmap.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index e294e3a6cc03..765626cad69a 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -13,7 +13,6 @@ #include "xilinx-core.h" #include -#include #include #include diff --git a/drivers/fsi/fsi-master-i2cr.c b/drivers/fsi/fsi-master-i2cr.c index d36a4328ad73..f76af608c421 100644 --- a/drivers/fsi/fsi-master-i2cr.c +++ b/drivers/fsi/fsi-master-i2cr.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "fsi-master-i2cr.h" diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index bb4d3700c934..56185accf459 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/fsi/i2cr-scom.c b/drivers/fsi/i2cr-scom.c index 3efca2e944bb..83b3c0348791 100644 --- a/drivers/fsi/i2cr-scom.c +++ b/drivers/fsi/i2cr-scom.c @@ -6,7 +6,6 @@ #include #include #include -#include #include "fsi-master-i2cr.h" #include "fsi-slave.h" diff --git a/drivers/gpib/eastwood/fluke_gpib.c b/drivers/gpib/eastwood/fluke_gpib.c index 2069c771ecef..1363f0a1f570 100644 --- a/drivers/gpib/eastwood/fluke_gpib.c +++ b/drivers/gpib/eastwood/fluke_gpib.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index bd2cc5f4f851..cdac37926f8e 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index 350feea2afa3..0410e3adbf54 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index bc6699a821ee..5ce89f52b4b5 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-altera-a10sr.c b/drivers/gpio/gpio-altera-a10sr.c index 4524c18a87e7..a41e5575ee37 100644 --- a/drivers/gpio/gpio-altera-a10sr.c +++ b/drivers/gpio/gpio-altera-a10sr.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index fe144360a88d..532e3360b70e 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index 85bd994d15d4..aa37579c9608 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -14,7 +14,6 @@ #include /* For WLAN GPIOs */ #include #include -#include #include #include diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index b1d32d590cf8..b0beffe48b7d 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpio/gpio-by-pinctrl.c b/drivers/gpio/gpio-by-pinctrl.c index ddfdc479d38a..7d7c48ce5163 100644 --- a/drivers/gpio/gpio-by-pinctrl.c +++ b/drivers/gpio/gpio-by-pinctrl.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-cros-ec.c b/drivers/gpio/gpio-cros-ec.c index 9deda8a9d11a..b48b684d817f 100644 --- a/drivers/gpio/gpio-cros-ec.c +++ b/drivers/gpio/gpio-cros-ec.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index c1f3d83a67c1..7b92b233fafe 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-en7523.c b/drivers/gpio/gpio-en7523.c index cf47afc578a9..14ad3ca9e623 100644 --- a/drivers/gpio/gpio-en7523.c +++ b/drivers/gpio/gpio-en7523.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-f7188x.c b/drivers/gpio/gpio-f7188x.c index 4d5b927ad70f..fb007b978729 100644 --- a/drivers/gpio/gpio-f7188x.c +++ b/drivers/gpio/gpio-f7188x.c @@ -48,7 +48,8 @@ /* * Nuvoton devices. */ -#define SIO_NCT6126D_ID 0xD283 /* NCT6126D chipset ID */ +#define SIO_NCT6126D_VER_A_ID 0xD283 /* NCT6126D version A chipset ID */ +#define SIO_NCT6126D_VER_B_ID 0xD284 /* NCT6126D version B chipset ID */ #define SIO_LD_GPIO_NUVOTON 0x07 /* GPIO logical device */ @@ -564,7 +565,8 @@ static int __init f7188x_find(int addr, struct f7188x_sio *sio) case SIO_F81865_ID: sio->type = f81865; break; - case SIO_NCT6126D_ID: + case SIO_NCT6126D_VER_A_ID: + case SIO_NCT6126D_VER_B_ID: sio->device = SIO_LD_GPIO_NUVOTON; sio->type = nct6126d; break; diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c index 66bdff36eb61..d0c8e16f1d48 100644 --- a/drivers/gpio/gpio-ge.c +++ b/drivers/gpio/gpio-ge.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-graniterapids.c b/drivers/gpio/gpio-graniterapids.c index 121bf29a27f5..2d0fe3abd5e0 100644 --- a/drivers/gpio/gpio-graniterapids.c +++ b/drivers/gpio/gpio-graniterapids.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-hisi.c b/drivers/gpio/gpio-hisi.c index d26298c8351b..42d41cf87ac7 100644 --- a/drivers/gpio/gpio-hisi.c +++ b/drivers/gpio/gpio-hisi.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpio/gpio-htc-egpio.c b/drivers/gpio/gpio-htc-egpio.c index d15423c718d0..25a4d4494f3c 100644 --- a/drivers/gpio/gpio-htc-egpio.c +++ b/drivers/gpio/gpio-htc-egpio.c @@ -268,6 +268,7 @@ static int __init egpio_probe(struct platform_device *pdev) struct gpio_chip *chip; unsigned int irq, irq_end; int i; + int ret; /* Initialize ei data structure. */ ei = devm_kzalloc(&pdev->dev, struct_size(ei, chip, pdata->num_chips), GFP_KERNEL); @@ -326,7 +327,10 @@ static int __init egpio_probe(struct platform_device *pdev) chip->base = pdata->chip[i].gpio_base; chip->ngpio = pdata->chip[i].num_gpios; - gpiochip_add_data(chip, &ei->chip[i]); + ret = devm_gpiochip_add_data(&pdev->dev, chip, &ei->chip[i]); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to register gpiochip %d\n", i); } /* Set initial pin values */ diff --git a/drivers/gpio/gpio-idt3243x.c b/drivers/gpio/gpio-idt3243x.c index 56f1f1e57b69..031b5c127fd6 100644 --- a/drivers/gpio/gpio-idt3243x.c +++ b/drivers/gpio/gpio-idt3243x.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpio/gpio-latch.c b/drivers/gpio/gpio-latch.c index 452a9ce61488..88757402ea96 100644 --- a/drivers/gpio/gpio-latch.c +++ b/drivers/gpio/gpio-latch.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-line-mux.c b/drivers/gpio/gpio-line-mux.c index 62548fbd3ca0..b4452d956bf0 100644 --- a/drivers/gpio/gpio-line-mux.c +++ b/drivers/gpio/gpio-line-mux.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-ltc4283.c b/drivers/gpio/gpio-ltc4283.c index 6609443c5d62..88aa6216006a 100644 --- a/drivers/gpio/gpio-ltc4283.c +++ b/drivers/gpio/gpio-ltc4283.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpio/gpio-max7360.c b/drivers/gpio/gpio-max7360.c index db92a43776a9..d12cf1dc8d57 100644 --- a/drivers/gpio/gpio-max7360.c +++ b/drivers/gpio/gpio-max7360.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-max77759.c b/drivers/gpio/gpio-max77759.c index c6bdac7fb44a..da3c77dd574e 100644 --- a/drivers/gpio/gpio-max77759.c +++ b/drivers/gpio/gpio-max77759.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c index 581a71872eab..78bcae130e0e 100644 --- a/drivers/gpio/gpio-mb86s7x.c +++ b/drivers/gpio/gpio-mb86s7x.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index 6668686a28ff..4e2f3381d82b 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-mmio.c b/drivers/gpio/gpio-mmio.c index 0941d034a49c..e9c531eef452 100644 --- a/drivers/gpio/gpio-mmio.c +++ b/drivers/gpio/gpio-mmio.c @@ -47,7 +47,6 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.` #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-mockup.c b/drivers/gpio/gpio-mockup.c index 91ff789c4fa6..1c6a2f3414f1 100644 --- a/drivers/gpio/gpio-mockup.c +++ b/drivers/gpio/gpio-mockup.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index bfe828734ee1..a6868f673831 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-mpfs.c b/drivers/gpio/gpio-mpfs.c index 1a4cf213c723..7f0751d7b1c4 100644 --- a/drivers/gpio/gpio-mpfs.c +++ b/drivers/gpio/gpio-mpfs.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c index a814885ccd5d..1b0b5247d3c9 100644 --- a/drivers/gpio/gpio-mt7621.c +++ b/drivers/gpio/gpio-mt7621.c @@ -187,6 +187,8 @@ mediatek_gpio_irq_type(struct irq_data *d, unsigned int type) struct mtk_gc *rg = gpiochip_get_data(gc); u32 mask = BIT(mt7621_gpio_hwirq_to_offset(d->hwirq, rg)); + guard(gpio_generic_lock_irqsave)(&rg->chip); + if (type == IRQ_TYPE_PROBE) { if ((rg->rising | rg->falling | rg->hlevel | rg->llevel) & mask) @@ -270,9 +272,9 @@ static const struct irq_chip mt7621_irq_chip = { }; static void -mt7621_gpio_remove(struct platform_device *pdev) +mt7621_gpio_remove(void *data) { - struct mtk *priv = platform_get_drvdata(pdev); + struct mtk *priv = data; int offset, virq; if (priv->gpio_irq > 0) @@ -464,23 +466,23 @@ mediatek_gpio_probe(struct platform_device *pdev) mtk->num_gpios = MTK_BANK_WIDTH * MTK_BANK_CNT; platform_set_drvdata(pdev, mtk); + if (mtk->gpio_irq > 0) { + ret = mt7621_gpio_irq_setup(pdev, mtk); + if (ret) + return ret; + } + + ret = devm_add_action_or_reset(dev, mt7621_gpio_remove, mtk); + if (ret) + return ret; + for (i = 0; i < MTK_BANK_CNT; i++) { ret = mediatek_gpio_bank_probe(dev, i); if (ret) return ret; } - if (mtk->gpio_irq > 0) { - ret = mt7621_gpio_irq_setup(pdev, mtk); - if (ret) - goto fail; - } - return 0; - -fail: - mt7621_gpio_remove(pdev); - return ret; } static const struct of_device_id mediatek_gpio_match[] = { @@ -491,7 +493,6 @@ MODULE_DEVICE_TABLE(of, mediatek_gpio_match); static struct platform_driver mediatek_gpio_driver = { .probe = mediatek_gpio_probe, - .remove = mt7621_gpio_remove, .driver = { .name = "mt7621_gpio", .of_match_table = mediatek_gpio_match, diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index c030d1f00abc..689dc6354c2d 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -1221,7 +1221,10 @@ static int mvebu_gpio_probe(struct platform_device *pdev) BUG(); } - devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip); + err = devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to register gpiochip\n"); /* Some MVEBU SoCs have simple PWM support for GPIO lines */ if (IS_REACHABLE(CONFIG_PWM)) { diff --git a/drivers/gpio/gpio-nomadik.c b/drivers/gpio/gpio-nomadik.c index e22b713166d7..5dc9f9d5912a 100644 --- a/drivers/gpio/gpio-nomadik.c +++ b/drivers/gpio/gpio-nomadik.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 2ee35e855e4d..f6b870b7b352 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index c942b959571b..4196916c4f94 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-qixis-fpga.c b/drivers/gpio/gpio-qixis-fpga.c index 3ced47db1521..b590572ac2bd 100644 --- a/drivers/gpio/gpio-qixis-fpga.c +++ b/drivers/gpio/gpio-qixis-fpga.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-realtek-otto.c b/drivers/gpio/gpio-realtek-otto.c index 37ef56f45318..4a606bad5848 100644 --- a/drivers/gpio/gpio-realtek-otto.c +++ b/drivers/gpio/gpio-realtek-otto.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-shared-proxy.c b/drivers/gpio/gpio-shared-proxy.c index 6941e4be6cf1..0f39d23ea9cb 100644 --- a/drivers/gpio/gpio-shared-proxy.c +++ b/drivers/gpio/gpio-shared-proxy.c @@ -9,8 +9,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -24,15 +25,13 @@ struct gpio_shared_proxy_data { }; static int -gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy, - int (*set_func)(struct gpio_desc *desc, int value), - int value) +gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy, int value) { struct gpio_shared_desc *shared_desc = proxy->shared_desc; struct gpio_desc *desc = shared_desc->desc; int ret = 0; - gpio_shared_lockdep_assert(shared_desc); + lockdep_assert_held(&shared_desc->mutex); if (value) { /* User wants to set value to high. */ @@ -46,7 +45,7 @@ gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy, * Current value is low, need to actually set value * to high. */ - ret = set_func(desc, 1); + ret = gpiod_set_value_cansleep(desc, 1); if (ret) goto out; } @@ -65,7 +64,7 @@ gpio_shared_proxy_set_unlocked(struct gpio_shared_proxy_data *proxy, /* We previously voted for high. */ if (shared_desc->highcnt == 1) { /* This is the last remaining vote for high, set value to low. */ - ret = set_func(desc, 0); + ret = gpiod_set_value_cansleep(desc, 0); if (ret) goto out; } @@ -89,7 +88,7 @@ static int gpio_shared_proxy_request(struct gpio_chip *gc, unsigned int offset) struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc); struct gpio_shared_desc *shared_desc = proxy->shared_desc; - guard(gpio_shared_desc_lock)(shared_desc); + guard(mutex)(&shared_desc->mutex); proxy->shared_desc->usecnt++; @@ -105,11 +104,10 @@ static void gpio_shared_proxy_free(struct gpio_chip *gc, unsigned int offset) struct gpio_shared_desc *shared_desc = proxy->shared_desc; int ret; - guard(gpio_shared_desc_lock)(shared_desc); + guard(mutex)(&shared_desc->mutex); if (proxy->voted_high) { - ret = gpio_shared_proxy_set_unlocked(proxy, - shared_desc->can_sleep ? gpiod_set_value_cansleep : gpiod_set_value, 0); + ret = gpio_shared_proxy_set_unlocked(proxy, 0); if (ret) dev_err(proxy->dev, "Failed to unset the shared GPIO value on release: %d\n", ret); @@ -129,7 +127,7 @@ static int gpio_shared_proxy_set_config(struct gpio_chip *gc, struct gpio_desc *desc = shared_desc->desc; int ret; - guard(gpio_shared_desc_lock)(shared_desc); + guard(mutex)(&shared_desc->mutex); if (shared_desc->usecnt > 1) { if (shared_desc->cfg != cfg) { @@ -157,7 +155,7 @@ static int gpio_shared_proxy_direction_input(struct gpio_chip *gc, struct gpio_desc *desc = shared_desc->desc; int dir; - guard(gpio_shared_desc_lock)(shared_desc); + guard(mutex)(&shared_desc->mutex); if (shared_desc->usecnt == 1) { dev_dbg(proxy->dev, @@ -187,7 +185,7 @@ static int gpio_shared_proxy_direction_output(struct gpio_chip *gc, struct gpio_desc *desc = shared_desc->desc; int ret, dir; - guard(gpio_shared_desc_lock)(shared_desc); + guard(mutex)(&shared_desc->mutex); if (shared_desc->usecnt == 1) { dev_dbg(proxy->dev, @@ -219,14 +217,7 @@ static int gpio_shared_proxy_direction_output(struct gpio_chip *gc, return -EPERM; } - return gpio_shared_proxy_set_unlocked(proxy, gpiod_direction_output, value); -} - -static int gpio_shared_proxy_get(struct gpio_chip *gc, unsigned int offset) -{ - struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc); - - return gpiod_get_value(proxy->shared_desc->desc); + return gpio_shared_proxy_set_unlocked(proxy, value); } static int gpio_shared_proxy_get_cansleep(struct gpio_chip *gc, @@ -237,29 +228,14 @@ static int gpio_shared_proxy_get_cansleep(struct gpio_chip *gc, return gpiod_get_value_cansleep(proxy->shared_desc->desc); } -static int gpio_shared_proxy_do_set(struct gpio_shared_proxy_data *proxy, - int (*set_func)(struct gpio_desc *desc, int value), - int value) -{ - guard(gpio_shared_desc_lock)(proxy->shared_desc); - - return gpio_shared_proxy_set_unlocked(proxy, set_func, value); -} - -static int gpio_shared_proxy_set(struct gpio_chip *gc, unsigned int offset, - int value) -{ - struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc); - - return gpio_shared_proxy_do_set(proxy, gpiod_set_value, value); -} - static int gpio_shared_proxy_set_cansleep(struct gpio_chip *gc, unsigned int offset, int value) { struct gpio_shared_proxy_data *proxy = gpiochip_get_data(gc); - return gpio_shared_proxy_do_set(proxy, gpiod_set_value_cansleep, value); + guard(mutex)(&proxy->shared_desc->mutex); + + return gpio_shared_proxy_set_unlocked(proxy, value); } static int gpio_shared_proxy_get_direction(struct gpio_chip *gc, @@ -302,20 +278,25 @@ static int gpio_shared_proxy_probe(struct auxiliary_device *adev, gc->label = dev_name(dev); gc->parent = dev; gc->owner = THIS_MODULE; - gc->can_sleep = shared_desc->can_sleep; + /* + * Under the descriptor mutex the proxy may call + * gpiod_set_config()/gpiod_direction_*(), which can reach pinctrl + * paths that take a mutex (e.g. gpiod_set_config() -> + * gpiochip_generic_config() -> pinctrl_gpio_set_config()), independent + * of the underlying chip's can_sleep. So the descriptor lock must be a + * mutex and the proxy gpiochip is therefore always sleeping; drive the + * underlying GPIO through the cansleep value accessors, which are valid + * for both sleeping and non-sleeping chips. + */ + gc->can_sleep = true; gc->request = gpio_shared_proxy_request; gc->free = gpio_shared_proxy_free; gc->set_config = gpio_shared_proxy_set_config; gc->direction_input = gpio_shared_proxy_direction_input; gc->direction_output = gpio_shared_proxy_direction_output; - if (gc->can_sleep) { - gc->set = gpio_shared_proxy_set_cansleep; - gc->get = gpio_shared_proxy_get_cansleep; - } else { - gc->set = gpio_shared_proxy_set; - gc->get = gpio_shared_proxy_get; - } + gc->set = gpio_shared_proxy_set_cansleep; + gc->get = gpio_shared_proxy_get_cansleep; gc->get_direction = gpio_shared_proxy_get_direction; gc->to_irq = gpio_shared_proxy_to_irq; diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index f0f570527cf2..ef1b779e8ea6 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-sl28cpld.c b/drivers/gpio/gpio-sl28cpld.c index 2195f88c2048..ca7a9b9bcf48 100644 --- a/drivers/gpio/gpio-sl28cpld.c +++ b/drivers/gpio/gpio-sl28cpld.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-sloppy-logic-analyzer.c b/drivers/gpio/gpio-sloppy-logic-analyzer.c index 969dddd3d6fa..2bbd308ca08e 100644 --- a/drivers/gpio/gpio-sloppy-logic-analyzer.c +++ b/drivers/gpio/gpio-sloppy-logic-analyzer.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-sprd.c b/drivers/gpio/gpio-sprd.c index 2cc8abe705cd..042a83f60eaa 100644 --- a/drivers/gpio/gpio-sprd.c +++ b/drivers/gpio/gpio-sprd.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 78fe133f5d32..ec378a4220a7 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -228,7 +228,7 @@ static int timbgpio_probe(struct platform_device *pdev) tgpio = devm_kzalloc(dev, sizeof(*tgpio), GFP_KERNEL); if (!tgpio) - return -EINVAL; + return -ENOMEM; gc = &tgpio->gpio; diff --git a/drivers/gpio/gpio-tn48m.c b/drivers/gpio/gpio-tn48m.c index cd4a80b22794..4fcd0bc24d55 100644 --- a/drivers/gpio/gpio-tn48m.c +++ b/drivers/gpio/gpio-tn48m.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c index 846f8688fec5..7d0d366be37a 100644 --- a/drivers/gpio/gpio-virtuser.c +++ b/drivers/gpio/gpio-virtuser.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-wcd934x.c b/drivers/gpio/gpio-wcd934x.c index 572b85e77370..b526493c84e4 100644 --- a/drivers/gpio/gpio-wcd934x.c +++ b/drivers/gpio/gpio-wcd934x.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019, Linaro Limited -#include #include #include #include diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c index 661259f026e1..3675456b1e9b 100644 --- a/drivers/gpio/gpio-xgene-sb.c +++ b/drivers/gpio/gpio-xgene-sb.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c index 7f3c98f9f902..fe0fba6ea902 100644 --- a/drivers/gpio/gpio-xra1403.c +++ b/drivers/gpio/gpio-xra1403.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c index af0158522ac5..288a86c8294a 100644 --- a/drivers/gpio/gpio-zevio.c +++ b/drivers/gpio/gpio-zevio.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index de72776fb154..495bd3d0ddf0 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -627,8 +627,7 @@ static void gpio_shared_release(struct kref *kref) shared_desc = entry->shared_desc; gpio_device_put(shared_desc->desc->gdev); - if (shared_desc->can_sleep) - mutex_destroy(&shared_desc->mutex); + mutex_destroy(&shared_desc->mutex); kfree(shared_desc); entry->shared_desc = NULL; } @@ -659,11 +658,7 @@ gpiod_shared_desc_create(struct gpio_shared_entry *entry) } shared_desc->desc = &gdev->descs[entry->offset]; - shared_desc->can_sleep = gpiod_cansleep(shared_desc->desc); - if (shared_desc->can_sleep) - mutex_init(&shared_desc->mutex); - else - spin_lock_init(&shared_desc->spinlock); + mutex_init(&shared_desc->mutex); return shared_desc; } diff --git a/drivers/gpio/gpiolib-shared.h b/drivers/gpio/gpiolib-shared.h index 15e72a8dcdb1..bbdc0ab7b647 100644 --- a/drivers/gpio/gpiolib-shared.h +++ b/drivers/gpio/gpiolib-shared.h @@ -3,10 +3,7 @@ #ifndef __LINUX_GPIO_SHARED_H #define __LINUX_GPIO_SHARED_H -#include -#include #include -#include struct gpio_device; struct gpio_desc; @@ -42,35 +39,12 @@ static inline int gpio_shared_add_proxy_lookup(struct device *consumer, struct gpio_shared_desc { struct gpio_desc *desc; - bool can_sleep; unsigned long cfg; unsigned int usecnt; unsigned int highcnt; - union { - struct mutex mutex; - spinlock_t spinlock; - }; + struct mutex mutex; /* serializes all proxy operations on this descriptor */ }; struct gpio_shared_desc *devm_gpiod_shared_get(struct device *dev); -DEFINE_LOCK_GUARD_1(gpio_shared_desc_lock, struct gpio_shared_desc, - if (_T->lock->can_sleep) - mutex_lock(&_T->lock->mutex); - else - spin_lock_irqsave(&_T->lock->spinlock, _T->flags), - if (_T->lock->can_sleep) - mutex_unlock(&_T->lock->mutex); - else - spin_unlock_irqrestore(&_T->lock->spinlock, _T->flags), - unsigned long flags) - -static inline void gpio_shared_lockdep_assert(struct gpio_shared_desc *shared_desc) -{ - if (shared_desc->can_sleep) - lockdep_assert_held(&shared_desc->mutex); - else - lockdep_assert_held(&shared_desc->spinlock); -} - #endif /* __LINUX_GPIO_SHARED_H */ diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index ba80542ead9d..5100e35027ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -70,7 +70,7 @@ amdgpu-y += amdgpu_device.o amdgpu_reg_access.o amdgpu_doorbell_mgr.o amdgpu_kms amdgpu_umc.o smu_v11_0_i2c.o amdgpu_fru_eeprom.o amdgpu_rap.o \ amdgpu_fw_attestation.o amdgpu_securedisplay.o \ amdgpu_eeprom.o amdgpu_mca.o amdgpu_psp_ta.o amdgpu_lsdma.o amdgpu_lockdep.o \ - amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_aca.o amdgpu_dev_coredump.o \ + amdgpu_ring_mux.o amdgpu_xcp.o amdgpu_seq64.o amdgpu_dev_coredump.o \ amdgpu_cper.o amdgpu_userq_fence.o amdgpu_eviction_fence.o amdgpu_ip.o amdgpu-$(CONFIG_PROC_FS) += amdgpu_fdinfo.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 7b09410d6d8f..dd8ea71077af 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -103,7 +104,6 @@ #include "amdgpu_smuio.h" #include "amdgpu_fdinfo.h" #include "amdgpu_mca.h" -#include "amdgpu_aca.h" #include "amdgpu_ras.h" #include "amdgpu_lockdep.h" #include "amdgpu_cper.h" @@ -113,6 +113,7 @@ #include "amdgpu_userq.h" #include "amdgpu_eviction_fence.h" #include "amdgpu_ip.h" +#include "amdgpu_sa.h" #if defined(CONFIG_DRM_AMD_ISP) #include "amdgpu_isp.h" #endif @@ -272,7 +273,6 @@ extern int amdgpu_ptl; extern uint amdgpu_hdmi_hpd_debounce_delay_ms; -#define AMDGPU_VM_MAX_NUM_CTX 4096 #define AMDGPU_SG_THRESHOLD (256*1024*1024) #define AMDGPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 #define AMDGPU_MAX_USEC_TIMEOUT 100000 /* 100 ms */ @@ -305,9 +305,10 @@ extern uint amdgpu_hdmi_hpd_debounce_delay_ms; /* reset mask */ #define AMDGPU_RESET_TYPE_FULL (1 << 0) /* full adapter reset, mode1/mode2/BACO/etc. */ -#define AMDGPU_RESET_TYPE_SOFT_RESET (1 << 1) /* IP level soft reset */ +#define AMDGPU_RESET_TYPE_SOFT_RECOVERY (1 << 1) /* soft recovery, eg. kill shaders */ #define AMDGPU_RESET_TYPE_PER_QUEUE (1 << 2) /* per queue */ #define AMDGPU_RESET_TYPE_PER_PIPE (1 << 3) /* per pipe */ +#define AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET (1 << 4) /* soft-resets an IP block */ /* max cursor sizes (in pixels) */ #define CIK_CURSOR_WIDTH 128 @@ -387,37 +388,6 @@ struct amdgpu_clock { uint32_t max_pixel_clock; }; -/* sub-allocation manager, it has to be protected by another lock. - * By conception this is an helper for other part of the driver - * like the indirect buffer or semaphore, which both have their - * locking. - * - * Principe is simple, we keep a list of sub allocation in offset - * order (first entry has offset == 0, last entry has the highest - * offset). - * - * When allocating new object we first check if there is room at - * the end total_size - (last_object_offset + last_object_size) >= - * alloc_size. If so we allocate new object there. - * - * When there is not enough room at the end, we start waiting for - * each sub object until we reach object_offset+object_size >= - * alloc_size, this object then become the sub object we return. - * - * Alignment can't be bigger than page size. - * - * Hole are not considered for allocation to keep things simple. - * Assumption is that there won't be hole (all object on same - * alignment). - */ - -struct amdgpu_sa_manager { - struct drm_suballoc_manager base; - struct amdgpu_bo *bo; - uint64_t gpu_addr; - void *cpu_ptr; -}; - /* * IRQS. */ @@ -446,8 +416,7 @@ struct amdgpu_fpriv { struct amdgpu_bo_va *prt_va; struct amdgpu_bo_va *csa_va; struct amdgpu_bo_va *seq64_va; - struct mutex bo_list_lock; - struct idr bo_list_handles; + struct xarray bo_list_handles; struct amdgpu_ctx_mgr ctx_mgr; struct amdgpu_userq_mgr userq_mgr; @@ -587,8 +556,6 @@ struct amdgpu_asic_funcs { /* invalidate hdp read cache */ void (*invalidate_hdp)(struct amdgpu_device *adev, struct amdgpu_ring *ring); - /* check if the asic needs a full reset of if soft reset will work */ - bool (*need_full_reset)(struct amdgpu_device *adev); /* initialize doorbell layout for specific asic*/ void (*init_doorbell_index)(struct amdgpu_device *adev); /* PCIe bandwidth usage */ @@ -851,6 +818,7 @@ struct amdgpu_device { struct dev_pm_domain vga_pm_domain; bool have_disp_power_ref; bool have_atomics_support; + bool is_sw_smu; /* BIOS */ bool is_atom_fw; @@ -1022,9 +990,6 @@ struct amdgpu_device { /* MCA */ struct amdgpu_mca mca; - /* ACA */ - struct amdgpu_aca aca; - /* CPER */ struct amdgpu_cper cper; @@ -1136,6 +1101,8 @@ struct amdgpu_device { bool debug_vm_userptr; bool debug_disable_ce_logs; bool debug_enable_ce_cs; + bool debug_hibernation_thaw_resume_gpu; + bool debug_disable_ip_block_soft_reset; /* Protection for the following isolation structure */ struct mutex enforce_isolation_mutex; @@ -1356,7 +1323,6 @@ int emu_soc_asic_init(struct amdgpu_device *adev); #define amdgpu_asic_read_bios_from_rom(adev, b, l) (adev)->asic_funcs->read_bios_from_rom((adev), (b), (l)) #define amdgpu_asic_read_register(adev, se, sh, offset, v)((adev)->asic_funcs->read_register((adev), (se), (sh), (offset), (v))) #define amdgpu_asic_get_config_memsize(adev) (adev)->asic_funcs->get_config_memsize((adev)) -#define amdgpu_asic_need_full_reset(adev) (adev)->asic_funcs->need_full_reset((adev)) #define amdgpu_asic_init_doorbell_index(adev) (adev)->asic_funcs->init_doorbell_index((adev)) #define amdgpu_asic_get_pcie_usage(adev, cnt0, cnt1) ((adev)->asic_funcs->get_pcie_usage((adev), (cnt0), (cnt1))) #define amdgpu_asic_need_reset_on_init(adev) (adev)->asic_funcs->need_reset_on_init((adev)) @@ -1468,6 +1434,8 @@ int amdgpu_enable_vblank_kms(struct drm_crtc *crtc); void amdgpu_disable_vblank_kms(struct drm_crtc *crtc); int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); +int amdgpu_proc_options_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp); /* * functions used by amdgpu_encoder.c diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c deleted file mode 100644 index db7858fe0c3d..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.c +++ /dev/null @@ -1,985 +0,0 @@ -/* - * Copyright 2023 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#include -#include "amdgpu.h" -#include "amdgpu_aca.h" -#include "amdgpu_ras.h" - -#define ACA_BANK_HWID(type, hwid, mcatype) [ACA_HWIP_TYPE_##type] = {hwid, mcatype} - -typedef int bank_handler_t(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type, void *data); - -static struct aca_hwip aca_hwid_mcatypes[ACA_HWIP_TYPE_COUNT] = { - ACA_BANK_HWID(SMU, 0x01, 0x01), - ACA_BANK_HWID(PCS_XGMI, 0x50, 0x00), - ACA_BANK_HWID(UMC, 0x96, 0x00), -}; - -static void aca_banks_init(struct aca_banks *banks) -{ - if (!banks) - return; - - memset(banks, 0, sizeof(*banks)); - INIT_LIST_HEAD(&banks->list); -} - -static int aca_banks_add_bank(struct aca_banks *banks, struct aca_bank *bank) -{ - struct aca_bank_node *node; - - if (!bank) - return -EINVAL; - - node = kvzalloc_obj(*node); - if (!node) - return -ENOMEM; - - memcpy(&node->bank, bank, sizeof(*bank)); - - INIT_LIST_HEAD(&node->node); - list_add_tail(&node->node, &banks->list); - - banks->nr_banks++; - - return 0; -} - -static void aca_banks_release(struct aca_banks *banks) -{ - struct aca_bank_node *node, *tmp; - - if (list_empty(&banks->list)) - return; - - list_for_each_entry_safe(node, tmp, &banks->list, node) { - list_del(&node->node); - kvfree(node); - banks->nr_banks--; - } -} - -static int aca_smu_get_valid_aca_count(struct amdgpu_device *adev, enum aca_smu_type type, u32 *count) -{ - struct amdgpu_aca *aca = &adev->aca; - const struct aca_smu_funcs *smu_funcs = aca->smu_funcs; - - if (!count) - return -EINVAL; - - if (!smu_funcs || !smu_funcs->get_valid_aca_count) - return -EOPNOTSUPP; - - return smu_funcs->get_valid_aca_count(adev, type, count); -} - -static struct aca_regs_dump { - const char *name; - int reg_idx; -} aca_regs[] = { - {"CONTROL", ACA_REG_IDX_CTL}, - {"STATUS", ACA_REG_IDX_STATUS}, - {"ADDR", ACA_REG_IDX_ADDR}, - {"MISC", ACA_REG_IDX_MISC0}, - {"CONFIG", ACA_REG_IDX_CONFIG}, - {"IPID", ACA_REG_IDX_IPID}, - {"SYND", ACA_REG_IDX_SYND}, - {"DESTAT", ACA_REG_IDX_DESTAT}, - {"DEADDR", ACA_REG_IDX_DEADDR}, - {"CONTROL_MASK", ACA_REG_IDX_CTL_MASK}, -}; - -static void aca_smu_bank_dump(struct amdgpu_device *adev, int idx, int total, struct aca_bank *bank, - struct ras_query_context *qctx) -{ - u64 event_id = qctx ? qctx->evid.event_id : RAS_EVENT_INVALID_ID; - int i; - - if (adev->debug_disable_ce_logs && - bank->smu_err_type == ACA_SMU_TYPE_CE && - !ACA_BANK_ERR_IS_DEFFERED(bank)) - return; - - RAS_EVENT_LOG(adev, event_id, HW_ERR "Accelerator Check Architecture events logged\n"); - /* plus 1 for output format, e.g: ACA[08/08]: xxxx */ - for (i = 0; i < ARRAY_SIZE(aca_regs); i++) - RAS_EVENT_LOG(adev, event_id, HW_ERR "ACA[%02d/%02d].%s=0x%016llx\n", - idx + 1, total, aca_regs[i].name, bank->regs[aca_regs[i].reg_idx]); - - if (ACA_REG__STATUS__SCRUB(bank->regs[ACA_REG_IDX_STATUS])) - RAS_EVENT_LOG(adev, event_id, HW_ERR "hardware error logged by the scrubber\n"); -} - -static bool aca_bank_hwip_is_matched(struct aca_bank *bank, enum aca_hwip_type type) -{ - - struct aca_hwip *hwip; - int hwid, mcatype; - u64 ipid; - - if (!bank || type == ACA_HWIP_TYPE_UNKNOW) - return false; - - hwip = &aca_hwid_mcatypes[type]; - if (!hwip->hwid) - return false; - - ipid = bank->regs[ACA_REG_IDX_IPID]; - hwid = ACA_REG__IPID__HARDWAREID(ipid); - mcatype = ACA_REG__IPID__MCATYPE(ipid); - - return hwip->hwid == hwid && hwip->mcatype == mcatype; -} - -static int aca_smu_get_valid_aca_banks(struct amdgpu_device *adev, enum aca_smu_type type, - int start, int count, - struct aca_banks *banks, struct ras_query_context *qctx) -{ - struct amdgpu_aca *aca = &adev->aca; - const struct aca_smu_funcs *smu_funcs = aca->smu_funcs; - struct aca_bank bank; - int i, max_count, ret; - - if (!count) - return 0; - - if (!smu_funcs || !smu_funcs->get_valid_aca_bank) - return -EOPNOTSUPP; - - switch (type) { - case ACA_SMU_TYPE_UE: - max_count = smu_funcs->max_ue_bank_count; - break; - case ACA_SMU_TYPE_CE: - max_count = smu_funcs->max_ce_bank_count; - break; - default: - return -EINVAL; - } - - if (start + count > max_count) - return -EINVAL; - - count = min_t(int, count, max_count); - for (i = 0; i < count; i++) { - memset(&bank, 0, sizeof(bank)); - ret = smu_funcs->get_valid_aca_bank(adev, type, start + i, &bank); - if (ret) - return ret; - - bank.smu_err_type = type; - - /* - * Poison being consumed when injecting a UE while running background workloads, - * which are unexpected. - */ - if (type == ACA_SMU_TYPE_UE && - ACA_REG__STATUS__POISON(bank.regs[ACA_REG_IDX_STATUS]) && - !aca_bank_hwip_is_matched(&bank, ACA_HWIP_TYPE_UMC)) - continue; - - aca_smu_bank_dump(adev, i, count, &bank, qctx); - - ret = aca_banks_add_bank(banks, &bank); - if (ret) - return ret; - } - - return 0; -} - -static bool aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type) -{ - const struct aca_bank_ops *bank_ops = handle->bank_ops; - - /* Parse all deferred errors with UMC aca handle */ - if (ACA_BANK_ERR_IS_DEFFERED(bank)) - return handle->hwip == ACA_HWIP_TYPE_UMC; - - if (!aca_bank_hwip_is_matched(bank, handle->hwip)) - return false; - - if (!bank_ops->aca_bank_is_valid) - return true; - - return bank_ops->aca_bank_is_valid(handle, bank, type, handle->data); -} - -static struct aca_bank_error *new_bank_error(struct aca_error *aerr, struct aca_bank_info *info) -{ - struct aca_bank_error *bank_error; - - bank_error = kvzalloc_obj(*bank_error); - if (!bank_error) - return NULL; - - INIT_LIST_HEAD(&bank_error->node); - memcpy(&bank_error->info, info, sizeof(*info)); - - mutex_lock(&aerr->lock); - list_add_tail(&bank_error->node, &aerr->list); - aerr->nr_errors++; - mutex_unlock(&aerr->lock); - - return bank_error; -} - -static struct aca_bank_error *find_bank_error(struct aca_error *aerr, struct aca_bank_info *info) -{ - struct aca_bank_error *bank_error = NULL; - struct aca_bank_info *tmp_info; - bool found = false; - - mutex_lock(&aerr->lock); - list_for_each_entry(bank_error, &aerr->list, node) { - tmp_info = &bank_error->info; - if (tmp_info->socket_id == info->socket_id && - tmp_info->die_id == info->die_id) { - found = true; - goto out_unlock; - } - } - -out_unlock: - mutex_unlock(&aerr->lock); - - return found ? bank_error : NULL; -} - -static void aca_bank_error_remove(struct aca_error *aerr, struct aca_bank_error *bank_error) -{ - if (!aerr || !bank_error) - return; - - list_del(&bank_error->node); - aerr->nr_errors--; - - kvfree(bank_error); -} - -static struct aca_bank_error *get_bank_error(struct aca_error *aerr, struct aca_bank_info *info) -{ - struct aca_bank_error *bank_error; - - if (!aerr || !info) - return NULL; - - bank_error = find_bank_error(aerr, info); - if (bank_error) - return bank_error; - - return new_bank_error(aerr, info); -} - -int aca_error_cache_log_bank_error(struct aca_handle *handle, struct aca_bank_info *info, - enum aca_error_type type, u64 count) -{ - struct aca_error_cache *error_cache = &handle->error_cache; - struct aca_bank_error *bank_error; - struct aca_error *aerr; - - if (!handle || !info || type >= ACA_ERROR_TYPE_COUNT) - return -EINVAL; - - if (!count) - return 0; - - aerr = &error_cache->errors[type]; - bank_error = get_bank_error(aerr, info); - if (!bank_error) - return -ENOMEM; - - bank_error->count += count; - - return 0; -} - -static int aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type) -{ - const struct aca_bank_ops *bank_ops = handle->bank_ops; - - if (!bank) - return -EINVAL; - - if (!bank_ops->aca_bank_parser) - return -EOPNOTSUPP; - - return bank_ops->aca_bank_parser(handle, bank, type, - handle->data); -} - -static int handler_aca_log_bank_error(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - int ret; - - ret = aca_bank_parser(handle, bank, type); - if (ret) - return ret; - - return 0; -} - -static int aca_dispatch_bank(struct aca_handle_manager *mgr, struct aca_bank *bank, - enum aca_smu_type type, bank_handler_t handler, void *data) -{ - struct aca_handle *handle; - int ret; - - if (list_empty(&mgr->list)) - return 0; - - list_for_each_entry(handle, &mgr->list, node) { - if (!aca_bank_is_valid(handle, bank, type)) - continue; - - ret = handler(handle, bank, type, data); - if (ret) - return ret; - } - - return 0; -} - -static int aca_dispatch_banks(struct aca_handle_manager *mgr, struct aca_banks *banks, - enum aca_smu_type type, bank_handler_t handler, void *data) -{ - struct aca_bank_node *node; - struct aca_bank *bank; - int ret; - - if (!mgr || !banks) - return -EINVAL; - - /* pre check to avoid unnecessary operations */ - if (list_empty(&mgr->list) || list_empty(&banks->list)) - return 0; - - list_for_each_entry(node, &banks->list, node) { - bank = &node->bank; - - ret = aca_dispatch_bank(mgr, bank, type, handler, data); - if (ret) - return ret; - } - - return 0; -} - -static bool aca_bank_should_update(struct amdgpu_device *adev, enum aca_smu_type type) -{ - struct amdgpu_aca *aca = &adev->aca; - bool ret = true; - - /* - * Because the UE Valid MCA count will only be cleared after reset, - * in order to avoid repeated counting of the error count, - * the aca bank is only updated once during the gpu recovery stage. - */ - if (type == ACA_SMU_TYPE_UE) { - if (amdgpu_ras_intr_triggered()) - ret = atomic_cmpxchg(&aca->ue_update_flag, 0, 1) == 0; - else - atomic_set(&aca->ue_update_flag, 0); - } - - return ret; -} - -static void aca_banks_generate_cper(struct amdgpu_device *adev, - enum aca_smu_type type, - struct aca_banks *banks, - int count) -{ - struct aca_bank_node *node; - struct aca_bank *bank; - int r; - - if (!adev->cper.enabled) - return; - - if (!banks || !count) { - dev_warn(adev->dev, "fail to generate cper records\n"); - return; - } - - /* UEs must be encoded into separate CPER entries */ - if (type == ACA_SMU_TYPE_UE) { - struct aca_banks de_banks; - - aca_banks_init(&de_banks); - list_for_each_entry(node, &banks->list, node) { - bank = &node->bank; - if (bank->aca_err_type == ACA_ERROR_TYPE_DEFERRED) { - r = aca_banks_add_bank(&de_banks, bank); - if (r) - dev_warn(adev->dev, "fail to add de banks, ret = %d\n", r); - } else { - if (amdgpu_cper_generate_ue_record(adev, bank)) - dev_warn(adev->dev, "fail to generate ue cper records\n"); - } - } - - if (!list_empty(&de_banks.list)) { - if (amdgpu_cper_generate_ce_records(adev, &de_banks, de_banks.nr_banks)) - dev_warn(adev->dev, "fail to generate de cper records\n"); - } - - aca_banks_release(&de_banks); - } else { - /* - * SMU_TYPE_CE banks are combined into 1 CPER entries, - * they could be CEs or DEs or both - */ - if (amdgpu_cper_generate_ce_records(adev, banks, count)) - dev_warn(adev->dev, "fail to generate ce cper records\n"); - } -} - -static int aca_banks_update(struct amdgpu_device *adev, enum aca_smu_type type, - bank_handler_t handler, struct ras_query_context *qctx, void *data) -{ - struct amdgpu_aca *aca = &adev->aca; - struct aca_banks banks; - u32 count = 0; - int ret; - - if (list_empty(&aca->mgr.list)) - return 0; - - if (!aca_bank_should_update(adev, type)) - return 0; - - ret = aca_smu_get_valid_aca_count(adev, type, &count); - if (ret) - return ret; - - if (!count) - return 0; - - aca_banks_init(&banks); - - ret = aca_smu_get_valid_aca_banks(adev, type, 0, count, &banks, qctx); - if (ret) - goto err_release_banks; - - if (list_empty(&banks.list)) { - ret = 0; - goto err_release_banks; - } - - ret = aca_dispatch_banks(&aca->mgr, &banks, type, - handler, data); - if (ret) - goto err_release_banks; - - aca_banks_generate_cper(adev, type, &banks, count); - -err_release_banks: - aca_banks_release(&banks); - - return ret; -} - -static int aca_log_aca_error_data(struct aca_bank_error *bank_error, enum aca_error_type type, struct ras_err_data *err_data) -{ - struct aca_bank_info *info; - struct amdgpu_smuio_mcm_config_info mcm_info; - u64 count; - - if (type >= ACA_ERROR_TYPE_COUNT) - return -EINVAL; - - count = bank_error->count; - if (!count) - return 0; - - info = &bank_error->info; - mcm_info.die_id = info->die_id; - mcm_info.socket_id = info->socket_id; - - switch (type) { - case ACA_ERROR_TYPE_UE: - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, count); - break; - case ACA_ERROR_TYPE_CE: - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, count); - break; - case ACA_ERROR_TYPE_DEFERRED: - amdgpu_ras_error_statistic_de_count(err_data, &mcm_info, count); - break; - default: - break; - } - - return 0; -} - -static int aca_log_aca_error(struct aca_handle *handle, enum aca_error_type type, struct ras_err_data *err_data) -{ - struct aca_error_cache *error_cache = &handle->error_cache; - struct aca_error *aerr = &error_cache->errors[type]; - struct aca_bank_error *bank_error, *tmp; - - mutex_lock(&aerr->lock); - - if (list_empty(&aerr->list)) - goto out_unlock; - - list_for_each_entry_safe(bank_error, tmp, &aerr->list, node) { - aca_log_aca_error_data(bank_error, type, err_data); - aca_bank_error_remove(aerr, bank_error); - } - -out_unlock: - mutex_unlock(&aerr->lock); - - return 0; -} - -static int __aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle, enum aca_error_type type, - struct ras_err_data *err_data, struct ras_query_context *qctx) -{ - enum aca_smu_type smu_type; - int ret; - - switch (type) { - case ACA_ERROR_TYPE_UE: - smu_type = ACA_SMU_TYPE_UE; - break; - case ACA_ERROR_TYPE_CE: - case ACA_ERROR_TYPE_DEFERRED: - smu_type = ACA_SMU_TYPE_CE; - break; - default: - return -EINVAL; - } - - /* update aca bank to aca source error_cache first */ - ret = aca_banks_update(adev, smu_type, handler_aca_log_bank_error, qctx, NULL); - if (ret) - return ret; - - /* DEs may contain in CEs or UEs */ - if (type != ACA_ERROR_TYPE_DEFERRED) - aca_log_aca_error(handle, ACA_ERROR_TYPE_DEFERRED, err_data); - - return aca_log_aca_error(handle, type, err_data); -} - -static bool aca_handle_is_valid(struct aca_handle *handle) -{ - if (!handle->mask || !list_empty(&handle->node)) - return false; - - return true; -} - -int amdgpu_aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle, - enum aca_error_type type, struct ras_err_data *err_data, - struct ras_query_context *qctx) -{ - if (!handle || !err_data) - return -EINVAL; - - if (aca_handle_is_valid(handle)) - return -EOPNOTSUPP; - - if ((type < 0) || (!(BIT(type) & handle->mask))) - return 0; - - return __aca_get_error_data(adev, handle, type, err_data, qctx); -} - -static void aca_error_init(struct aca_error *aerr, enum aca_error_type type) -{ - mutex_init(&aerr->lock); - INIT_LIST_HEAD(&aerr->list); - aerr->type = type; - aerr->nr_errors = 0; -} - -static void aca_init_error_cache(struct aca_handle *handle) -{ - struct aca_error_cache *error_cache = &handle->error_cache; - int type; - - for (type = ACA_ERROR_TYPE_UE; type < ACA_ERROR_TYPE_COUNT; type++) - aca_error_init(&error_cache->errors[type], type); -} - -static void aca_error_fini(struct aca_error *aerr) -{ - struct aca_bank_error *bank_error, *tmp; - - mutex_lock(&aerr->lock); - if (list_empty(&aerr->list)) - goto out_unlock; - - list_for_each_entry_safe(bank_error, tmp, &aerr->list, node) - aca_bank_error_remove(aerr, bank_error); - -out_unlock: - mutex_unlock(&aerr->lock); - mutex_destroy(&aerr->lock); -} - -static void aca_fini_error_cache(struct aca_handle *handle) -{ - struct aca_error_cache *error_cache = &handle->error_cache; - int type; - - for (type = ACA_ERROR_TYPE_UE; type < ACA_ERROR_TYPE_COUNT; type++) - aca_error_fini(&error_cache->errors[type]); -} - -static int add_aca_handle(struct amdgpu_device *adev, struct aca_handle_manager *mgr, struct aca_handle *handle, - const char *name, const struct aca_info *ras_info, void *data) -{ - memset(handle, 0, sizeof(*handle)); - - handle->adev = adev; - handle->mgr = mgr; - handle->name = name; - handle->hwip = ras_info->hwip; - handle->mask = ras_info->mask; - handle->bank_ops = ras_info->bank_ops; - handle->data = data; - aca_init_error_cache(handle); - - INIT_LIST_HEAD(&handle->node); - list_add_tail(&handle->node, &mgr->list); - mgr->nr_handles++; - - return 0; -} - -static ssize_t aca_sysfs_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct aca_handle *handle = container_of(attr, struct aca_handle, aca_attr); - - /* NOTE: the aca cache will be auto cleared once read, - * So the driver should unify the query entry point, forward request to ras query interface directly */ - return amdgpu_ras_aca_sysfs_read(dev, attr, handle, buf, handle->data); -} - -static int add_aca_sysfs(struct amdgpu_device *adev, struct aca_handle *handle) -{ - struct device_attribute *aca_attr = &handle->aca_attr; - - snprintf(handle->attr_name, sizeof(handle->attr_name) - 1, "aca_%s", handle->name); - aca_attr->show = aca_sysfs_read; - aca_attr->attr.name = handle->attr_name; - aca_attr->attr.mode = S_IRUGO; - sysfs_attr_init(&aca_attr->attr); - - return sysfs_add_file_to_group(&adev->dev->kobj, - &aca_attr->attr, - "ras"); -} - -int amdgpu_aca_add_handle(struct amdgpu_device *adev, struct aca_handle *handle, - const char *name, const struct aca_info *ras_info, void *data) -{ - struct amdgpu_aca *aca = &adev->aca; - int ret; - - if (!amdgpu_aca_is_enabled(adev)) - return 0; - - ret = add_aca_handle(adev, &aca->mgr, handle, name, ras_info, data); - if (ret) - return ret; - - return add_aca_sysfs(adev, handle); -} - -static void remove_aca_handle(struct aca_handle *handle) -{ - struct aca_handle_manager *mgr = handle->mgr; - - aca_fini_error_cache(handle); - list_del(&handle->node); - mgr->nr_handles--; -} - -static void remove_aca_sysfs(struct aca_handle *handle) -{ - struct amdgpu_device *adev = handle->adev; - struct device_attribute *aca_attr = &handle->aca_attr; - - if (adev->dev->kobj.sd) - sysfs_remove_file_from_group(&adev->dev->kobj, - &aca_attr->attr, - "ras"); -} - -void amdgpu_aca_remove_handle(struct aca_handle *handle) -{ - if (!handle || list_empty(&handle->node)) - return; - - remove_aca_sysfs(handle); - remove_aca_handle(handle); -} - -static int aca_manager_init(struct aca_handle_manager *mgr) -{ - INIT_LIST_HEAD(&mgr->list); - mgr->nr_handles = 0; - - return 0; -} - -static void aca_manager_fini(struct aca_handle_manager *mgr) -{ - struct aca_handle *handle, *tmp; - - if (list_empty(&mgr->list)) - return; - - list_for_each_entry_safe(handle, tmp, &mgr->list, node) - amdgpu_aca_remove_handle(handle); -} - -bool amdgpu_aca_is_enabled(struct amdgpu_device *adev) -{ - return (adev->aca.is_enabled || - adev->debug_enable_ras_aca); -} - -int amdgpu_aca_init(struct amdgpu_device *adev) -{ - struct amdgpu_aca *aca = &adev->aca; - int ret; - - atomic_set(&aca->ue_update_flag, 0); - - ret = aca_manager_init(&aca->mgr); - if (ret) - return ret; - - return 0; -} - -void amdgpu_aca_fini(struct amdgpu_device *adev) -{ - struct amdgpu_aca *aca = &adev->aca; - - aca_manager_fini(&aca->mgr); - - atomic_set(&aca->ue_update_flag, 0); -} - -int amdgpu_aca_reset(struct amdgpu_device *adev) -{ - struct amdgpu_aca *aca = &adev->aca; - - atomic_set(&aca->ue_update_flag, 0); - - return 0; -} - -void amdgpu_aca_set_smu_funcs(struct amdgpu_device *adev, const struct aca_smu_funcs *smu_funcs) -{ - struct amdgpu_aca *aca = &adev->aca; - - WARN_ON(aca->smu_funcs); - aca->smu_funcs = smu_funcs; -} - -int aca_bank_info_decode(struct aca_bank *bank, struct aca_bank_info *info) -{ - u64 ipid; - u32 instidhi, instidlo; - - if (!bank || !info) - return -EINVAL; - - ipid = bank->regs[ACA_REG_IDX_IPID]; - info->hwid = ACA_REG__IPID__HARDWAREID(ipid); - info->mcatype = ACA_REG__IPID__MCATYPE(ipid); - /* - * Unfied DieID Format: SAASS. A:AID, S:Socket. - * Unfied DieID[4:4] = InstanceId[0:0] - * Unfied DieID[0:3] = InstanceIdHi[0:3] - */ - instidhi = ACA_REG__IPID__INSTANCEIDHI(ipid); - instidlo = ACA_REG__IPID__INSTANCEIDLO(ipid); - info->die_id = ((instidhi >> 2) & 0x03); - info->socket_id = ((instidlo & 0x1) << 2) | (instidhi & 0x03); - - return 0; -} - -static int aca_bank_get_error_code(struct amdgpu_device *adev, struct aca_bank *bank) -{ - struct amdgpu_aca *aca = &adev->aca; - const struct aca_smu_funcs *smu_funcs = aca->smu_funcs; - - if (!smu_funcs || !smu_funcs->parse_error_code) - return -EOPNOTSUPP; - - return smu_funcs->parse_error_code(adev, bank); -} - -int aca_bank_check_error_codes(struct amdgpu_device *adev, struct aca_bank *bank, int *err_codes, int size) -{ - int i, error_code; - - if (!bank || !err_codes) - return -EINVAL; - - error_code = aca_bank_get_error_code(adev, bank); - if (error_code < 0) - return error_code; - - for (i = 0; i < size; i++) { - if (err_codes[i] == error_code) - return 0; - } - - return -EINVAL; -} - -int amdgpu_aca_smu_set_debug_mode(struct amdgpu_device *adev, bool en) -{ - struct amdgpu_aca *aca = &adev->aca; - const struct aca_smu_funcs *smu_funcs = aca->smu_funcs; - - if (!smu_funcs || !smu_funcs->set_debug_mode) - return -EOPNOTSUPP; - - return smu_funcs->set_debug_mode(adev, en); -} - -#if defined(CONFIG_DEBUG_FS) -static int amdgpu_aca_smu_debug_mode_set(void *data, u64 val) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)data; - int ret; - - ret = amdgpu_ras_set_aca_debug_mode(adev, val ? true : false); - if (ret) - return ret; - - dev_info(adev->dev, "amdgpu set smu aca debug mode %s success\n", val ? "on" : "off"); - - return 0; -} - -static void aca_dump_entry(struct seq_file *m, struct aca_bank *bank, enum aca_smu_type type, int idx) -{ - struct aca_bank_info info; - int i, ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return; - - seq_printf(m, "aca entry[%d].type: %s\n", idx, type == ACA_SMU_TYPE_UE ? "UE" : "CE"); - seq_printf(m, "aca entry[%d].info: socketid:%d aid:%d hwid:0x%03x mcatype:0x%04x\n", - idx, info.socket_id, info.die_id, info.hwid, info.mcatype); - - for (i = 0; i < ARRAY_SIZE(aca_regs); i++) - seq_printf(m, "aca entry[%d].regs[%d]: 0x%016llx\n", idx, aca_regs[i].reg_idx, bank->regs[aca_regs[i].reg_idx]); -} - -struct aca_dump_context { - struct seq_file *m; - int idx; -}; - -static int handler_aca_bank_dump(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct aca_dump_context *ctx = (struct aca_dump_context *)data; - - aca_dump_entry(ctx->m, bank, type, ctx->idx++); - - return handler_aca_log_bank_error(handle, bank, type, NULL); -} - -static int aca_dump_show(struct seq_file *m, enum aca_smu_type type) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)m->private; - struct aca_dump_context context = { - .m = m, - .idx = 0, - }; - - return aca_banks_update(adev, type, handler_aca_bank_dump, NULL, (void *)&context); -} - -static int aca_dump_ce_show(struct seq_file *m, void *unused) -{ - return aca_dump_show(m, ACA_SMU_TYPE_CE); -} - -static int aca_dump_ce_open(struct inode *inode, struct file *file) -{ - return single_open(file, aca_dump_ce_show, inode->i_private); -} - -static const struct file_operations aca_ce_dump_debug_fops = { - .owner = THIS_MODULE, - .open = aca_dump_ce_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int aca_dump_ue_show(struct seq_file *m, void *unused) -{ - return aca_dump_show(m, ACA_SMU_TYPE_UE); -} - -static int aca_dump_ue_open(struct inode *inode, struct file *file) -{ - return single_open(file, aca_dump_ue_show, inode->i_private); -} - -static const struct file_operations aca_ue_dump_debug_fops = { - .owner = THIS_MODULE, - .open = aca_dump_ue_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -DEFINE_DEBUGFS_ATTRIBUTE(aca_debug_mode_fops, NULL, amdgpu_aca_smu_debug_mode_set, "%llu\n"); -#endif - -void amdgpu_aca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root) -{ -#if defined(CONFIG_DEBUG_FS) - if (!root) - return; - - debugfs_create_file("aca_debug_mode", 0200, root, adev, &aca_debug_mode_fops); - debugfs_create_file("aca_ue_dump", 0400, root, adev, &aca_ue_dump_debug_fops); - debugfs_create_file("aca_ce_dump", 0400, root, adev, &aca_ce_dump_debug_fops); -#endif -} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h deleted file mode 100644 index 38c88897e1ec..000000000000 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_aca.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright 2023 Advanced Micro Devices, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef __AMDGPU_ACA_H__ -#define __AMDGPU_ACA_H__ - -#include - -struct ras_err_data; -struct ras_query_context; - -#define ACA_MAX_REGS_COUNT (16) - -#define ACA_REG_FIELD(x, h, l) (((x) & GENMASK_ULL(h, l)) >> l) -#define ACA_REG__STATUS__VAL(x) ACA_REG_FIELD(x, 63, 63) -#define ACA_REG__STATUS__OVERFLOW(x) ACA_REG_FIELD(x, 62, 62) -#define ACA_REG__STATUS__UC(x) ACA_REG_FIELD(x, 61, 61) -#define ACA_REG__STATUS__EN(x) ACA_REG_FIELD(x, 60, 60) -#define ACA_REG__STATUS__MISCV(x) ACA_REG_FIELD(x, 59, 59) -#define ACA_REG__STATUS__ADDRV(x) ACA_REG_FIELD(x, 58, 58) -#define ACA_REG__STATUS__PCC(x) ACA_REG_FIELD(x, 57, 57) -#define ACA_REG__STATUS__ERRCOREIDVAL(x) ACA_REG_FIELD(x, 56, 56) -#define ACA_REG__STATUS__TCC(x) ACA_REG_FIELD(x, 55, 55) -#define ACA_REG__STATUS__SYNDV(x) ACA_REG_FIELD(x, 53, 53) -#define ACA_REG__STATUS__CECC(x) ACA_REG_FIELD(x, 46, 46) -#define ACA_REG__STATUS__UECC(x) ACA_REG_FIELD(x, 45, 45) -#define ACA_REG__STATUS__DEFERRED(x) ACA_REG_FIELD(x, 44, 44) -#define ACA_REG__STATUS__POISON(x) ACA_REG_FIELD(x, 43, 43) -#define ACA_REG__STATUS__SCRUB(x) ACA_REG_FIELD(x, 40, 40) -#define ACA_REG__STATUS__ERRCOREID(x) ACA_REG_FIELD(x, 37, 32) -#define ACA_REG__STATUS__ADDRLSB(x) ACA_REG_FIELD(x, 29, 24) -#define ACA_REG__STATUS__ERRORCODEEXT(x) ACA_REG_FIELD(x, 21, 16) -#define ACA_REG__STATUS__ERRORCODE(x) ACA_REG_FIELD(x, 15, 0) - -#define ACA_REG__IPID__MCATYPE(x) ACA_REG_FIELD(x, 63, 48) -#define ACA_REG__IPID__INSTANCEIDHI(x) ACA_REG_FIELD(x, 47, 44) -#define ACA_REG__IPID__HARDWAREID(x) ACA_REG_FIELD(x, 43, 32) -#define ACA_REG__IPID__INSTANCEIDLO(x) ACA_REG_FIELD(x, 31, 0) - -#define ACA_REG__MISC0__VALID(x) ACA_REG_FIELD(x, 63, 63) -#define ACA_REG__MISC0__OVRFLW(x) ACA_REG_FIELD(x, 48, 48) -#define ACA_REG__MISC0__ERRCNT(x) ACA_REG_FIELD(x, 43, 32) - -#define ACA_REG__SYND__ERRORINFORMATION(x) ACA_REG_FIELD(x, 17, 0) - -/* NOTE: The following codes refers to the smu header file */ -#define ACA_EXTERROR_CODE_CE 0x3a -#define ACA_EXTERROR_CODE_FAULT 0x3b - -#define ACA_ERROR_UE_MASK BIT_MASK(ACA_ERROR_TYPE_UE) -#define ACA_ERROR_CE_MASK BIT_MASK(ACA_ERROR_TYPE_CE) -#define ACA_ERROR_DEFERRED_MASK BIT_MASK(ACA_ERROR_TYPE_DEFERRED) - -#define mmSMNAID_AID0_MCA_SMU 0x03b30400 /* SMN AID AID0 */ -#define mmSMNAID_XCD0_MCA_SMU 0x36430400 /* SMN AID XCD0 */ -#define mmSMNAID_XCD1_MCA_SMU 0x38430400 /* SMN AID XCD1 */ -#define mmSMNXCD_XCD0_MCA_SMU 0x40430400 /* SMN XCD XCD0 */ - -#define ACA_BANK_ERR_IS_DEFFERED(bank) \ - (ACA_REG__STATUS__POISON((bank)->regs[ACA_REG_IDX_STATUS]) || \ - ACA_REG__STATUS__DEFERRED((bank)->regs[ACA_REG_IDX_STATUS])) - -enum aca_reg_idx { - ACA_REG_IDX_CTL = 0, - ACA_REG_IDX_STATUS = 1, - ACA_REG_IDX_ADDR = 2, - ACA_REG_IDX_MISC0 = 3, - ACA_REG_IDX_CONFIG = 4, - ACA_REG_IDX_IPID = 5, - ACA_REG_IDX_SYND = 6, - ACA_REG_IDX_DESTAT = 8, - ACA_REG_IDX_DEADDR = 9, - ACA_REG_IDX_CTL_MASK = 10, - ACA_REG_IDX_COUNT = 16, -}; - -enum aca_hwip_type { - ACA_HWIP_TYPE_UNKNOW = -1, - ACA_HWIP_TYPE_PSP = 0, - ACA_HWIP_TYPE_UMC, - ACA_HWIP_TYPE_SMU, - ACA_HWIP_TYPE_PCS_XGMI, - ACA_HWIP_TYPE_COUNT, -}; - -enum aca_error_type { - ACA_ERROR_TYPE_INVALID = -1, - ACA_ERROR_TYPE_UE = 0, - ACA_ERROR_TYPE_CE, - ACA_ERROR_TYPE_DEFERRED, - ACA_ERROR_TYPE_COUNT -}; - -enum aca_smu_type { - ACA_SMU_TYPE_INVALID = -1, - ACA_SMU_TYPE_UE = 0, - ACA_SMU_TYPE_CE, - ACA_SMU_TYPE_COUNT, -}; - -struct aca_hwip { - int hwid; - int mcatype; -}; - -struct aca_bank { - enum aca_error_type aca_err_type; - enum aca_smu_type smu_err_type; - u64 regs[ACA_MAX_REGS_COUNT]; -}; - -struct aca_bank_node { - struct aca_bank bank; - struct list_head node; -}; - -struct aca_banks { - int nr_banks; - struct list_head list; -}; - -struct aca_bank_info { - int die_id; - int socket_id; - int hwid; - int mcatype; -}; - -struct aca_bank_error { - struct list_head node; - struct aca_bank_info info; - u64 count; -}; - -struct aca_error { - struct list_head list; - struct mutex lock; - enum aca_error_type type; - int nr_errors; -}; - -struct aca_handle_manager { - struct list_head list; - int nr_handles; -}; - -struct aca_error_cache { - struct aca_error errors[ACA_ERROR_TYPE_COUNT]; -}; - -struct aca_handle { - struct list_head node; - enum aca_hwip_type hwip; - struct amdgpu_device *adev; - struct aca_handle_manager *mgr; - struct aca_error_cache error_cache; - const struct aca_bank_ops *bank_ops; - struct device_attribute aca_attr; - char attr_name[64]; - const char *name; - u32 mask; - void *data; -}; - -struct aca_bank_ops { - int (*aca_bank_parser)(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type, void *data); - bool (*aca_bank_is_valid)(struct aca_handle *handle, struct aca_bank *bank, enum aca_smu_type type, - void *data); -}; - -struct aca_smu_funcs { - int max_ue_bank_count; - int max_ce_bank_count; - int (*set_debug_mode)(struct amdgpu_device *adev, bool enable); - int (*get_valid_aca_count)(struct amdgpu_device *adev, enum aca_smu_type type, u32 *count); - int (*get_valid_aca_bank)(struct amdgpu_device *adev, enum aca_smu_type type, int idx, struct aca_bank *bank); - int (*parse_error_code)(struct amdgpu_device *adev, struct aca_bank *bank); -}; - -struct amdgpu_aca { - struct aca_handle_manager mgr; - const struct aca_smu_funcs *smu_funcs; - atomic_t ue_update_flag; - bool is_enabled; -}; - -struct aca_info { - enum aca_hwip_type hwip; - const struct aca_bank_ops *bank_ops; - u32 mask; -}; - -int amdgpu_aca_init(struct amdgpu_device *adev); -void amdgpu_aca_fini(struct amdgpu_device *adev); -int amdgpu_aca_reset(struct amdgpu_device *adev); -void amdgpu_aca_set_smu_funcs(struct amdgpu_device *adev, const struct aca_smu_funcs *smu_funcs); -bool amdgpu_aca_is_enabled(struct amdgpu_device *adev); - -int aca_bank_info_decode(struct aca_bank *bank, struct aca_bank_info *info); -int aca_bank_check_error_codes(struct amdgpu_device *adev, struct aca_bank *bank, int *err_codes, int size); - -int amdgpu_aca_add_handle(struct amdgpu_device *adev, struct aca_handle *handle, - const char *name, const struct aca_info *aca_info, void *data); -void amdgpu_aca_remove_handle(struct aca_handle *handle); -int amdgpu_aca_get_error_data(struct amdgpu_device *adev, struct aca_handle *handle, - enum aca_error_type type, struct ras_err_data *err_data, - struct ras_query_context *qctx); -int amdgpu_aca_smu_set_debug_mode(struct amdgpu_device *adev, bool en); -void amdgpu_aca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root); -int aca_error_cache_log_bank_error(struct aca_handle *handle, struct aca_bank_info *info, - enum aca_error_type type, u64 count); -#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c index 4c732e0f776e..9014678d75ab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c @@ -508,6 +508,7 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block) u32 val = 0; u32 count = 0; struct amdgpu_device *adev = ip_block->adev; + int ret = 0; /* return early if no ACP */ if (!adev->acp.acp_genpd) { @@ -529,7 +530,8 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block) break; if (--count == 0) { dev_err(&adev->pdev->dev, "Failed to reset ACP\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } udelay(100); } @@ -546,21 +548,24 @@ static int acp_hw_fini(struct amdgpu_ip_block *ip_block) break; if (--count == 0) { dev_err(&adev->pdev->dev, "Failed to reset ACP\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } udelay(100); } - +out: device_for_each_child(adev->acp.parent, NULL, acp_genpd_remove_device); mfd_remove_devices(adev->acp.parent); kfree(adev->acp.i2s_pdata); kfree(adev->acp.acp_res); + pm_genpd_remove(&adev->acp.acp_genpd->gpd); kfree(adev->acp.acp_genpd); + adev->acp.acp_genpd = NULL; kfree(adev->acp.acp_cell); - return 0; + return ret; } static int acp_suspend(struct amdgpu_ip_block *ip_block) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 516ab9cf88fc..7f5abb03be1b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -140,13 +140,15 @@ static struct amdgpu_acpi_priv { * @atif: atif structure * @function: the ATIF function to execute * @params: ATIF function params + * @min_size: minimum size of the expected output buffer in bytes * * Executes the requested ATIF function (all asics). * Returns a pointer to the acpi output buffer. */ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, int function, - struct acpi_buffer *params) + struct acpi_buffer *params, + size_t min_size) { acpi_status status; union acpi_object *obj; @@ -189,6 +191,28 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, return NULL; } + if (obj->buffer.length < sizeof(u16)) { + DRM_DEBUG_DRIVER("ATIF buffer too small to hold size field: %u\n", + obj->buffer.length); + kfree(obj); + return NULL; + } + + if (obj->buffer.length < *(u16 *)obj->buffer.pointer) { + DRM_DEBUG_DRIVER("ATIF buffer length mismatch: reported %u, actual %u\n", + *(u16 *)obj->buffer.pointer, + obj->buffer.length); + kfree(obj); + return NULL; + } + + if (*(u16 *)obj->buffer.pointer < min_size) { + DRM_DEBUG_DRIVER("ATIF buffer too small: expected %zu, got %u\n", + min_size, *(u16 *)obj->buffer.pointer); + kfree(obj); + return NULL; + } + return obj; } @@ -251,19 +275,14 @@ int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) size_t size; int err = 0; - info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL, + sizeof(output)); if (!info) return -EIO; memset(&output, 0, sizeof(output)); - size = *(u16 *) info->buffer.pointer; - if (size < 12) { - DRM_INFO("ATIF buffer is too small: %zu\n", size); - err = -EINVAL; - goto out; - } - size = min(sizeof(output), size); + size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer); memcpy(&output, info->buffer.pointer, size); @@ -273,7 +292,6 @@ int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) amdgpu_atif_parse_notification(&atif->notifications, output.notification_mask); amdgpu_atif_parse_functions(&atif->functions, output.function_bits); -out: kfree(info); return err; } @@ -299,20 +317,14 @@ int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif) int err = 0; info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, - NULL); + NULL, offsetof(struct atif_system_params, command_code)); if (!info) { err = -EIO; goto out; } - size = *(u16 *) info->buffer.pointer; - if (size < 10) { - err = -EINVAL; - goto out; - } - memset(¶ms, 0, sizeof(params)); - size = min(sizeof(params), size); + size = min(sizeof(params), (size_t)*(u16 *)info->buffer.pointer); memcpy(¶ms, info->buffer.pointer, size); DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", @@ -376,20 +388,14 @@ int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif) info = amdgpu_atif_call(atif, ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS, - ¶ms); + ¶ms, offsetof(struct atif_qbtc_output, data_points)); if (!info) { err = -EIO; goto out; } - size = *(u16 *) info->buffer.pointer; - if (size < 10) { - err = -EINVAL; - goto out; - } - memset(&characteristics, 0, sizeof(characteristics)); - size = min(sizeof(characteristics), size); + size = min(sizeof(characteristics), (size_t)*(u16 *)info->buffer.pointer); memcpy(&characteristics, info->buffer.pointer, size); atif->backlight_caps.caps_valid = true; @@ -427,24 +433,18 @@ static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif, int count = 0; info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, - NULL); + NULL, sizeof(*req)); if (!info) return -EIO; - size = *(u16 *)info->buffer.pointer; - if (size < 0xd) { - count = -EINVAL; - goto out; - } memset(req, 0, sizeof(*req)); - size = min(sizeof(*req), size); + size = min(sizeof(*req), (size_t)*(u16 *)info->buffer.pointer); memcpy(req, info->buffer.pointer, size); DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); count = hweight32(req->pending); -out: kfree(info); return count; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index da325863ad76..c693c508df1a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -957,3 +957,17 @@ int amdgpu_amdkfd_config_sq_perfmon(struct amdgpu_device *adev, uint32_t xcp_id, return r; } + +/* Reset an MES queue */ +int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev, + uint32_t node_id, + int queue_type, + int pipe, int queue, + unsigned int db) +{ + if (!adev->kfd.init_complete) + return 0; + + return kgd2kfd_reset_mes_queue(adev->kfd.dev, node_id, queue_type, + pipe, queue, db); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index e443a7277299..338412a750ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -210,6 +210,7 @@ int amdgpu_amdkfd_evict_userptr(struct mmu_interval_notifier *mni, int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, uint32_t domain, struct dma_fence *fence); +int amdgpu_amdkfd_set_sigbus_delay(struct task_struct *task, u32 ms); #else static inline bool amdkfd_fence_check_mm(struct dma_fence *f, struct mm_struct *mm) @@ -241,6 +242,11 @@ int amdgpu_amdkfd_bo_validate_and_fence(struct amdgpu_bo *bo, { return 0; } +static inline +int amdgpu_amdkfd_set_sigbus_delay(struct task_struct *task, u32 ms) +{ + return -EOPNOTSUPP; +} #endif /* Shared API */ int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t size, @@ -275,7 +281,11 @@ int amdgpu_amdkfd_stop_sched(struct amdgpu_device *adev, uint32_t node_id); int amdgpu_amdkfd_config_sq_perfmon(struct amdgpu_device *adev, uint32_t xcp_id, bool core_override_enable, bool reg_override_enable, bool perfmon_override_enable); bool amdgpu_amdkfd_compute_active(struct amdgpu_device *adev, uint32_t node_id); - +int amdgpu_amdkfd_reset_mes_queue(struct amdgpu_device *adev, + uint32_t node_id, + int queue_type, + int pipe, int queue, + unsigned int db); /* Read user wptr from a specified user address space with page fault * disabled. The memory must be pinned and mapped to the hardware when @@ -326,9 +336,9 @@ int amdgpu_amdkfd_gpuvm_unmap_memory_from_gpu( int amdgpu_amdkfd_gpuvm_dmaunmap_mem(struct kgd_mem *mem, void *drm_priv); int amdgpu_amdkfd_gpuvm_sync_memory( struct amdgpu_device *adev, struct kgd_mem *mem, bool intr); -int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, - void **kptr, uint64_t *size); -void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct kgd_mem *mem); +int amdgpu_amdkfd_gpuvm_map_bo_to_kernel(struct kgd_mem *mem, void **kptr, + u64 *size, u32 domain); +void amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(struct kgd_mem *mem); int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo_gart); @@ -446,6 +456,9 @@ bool kgd2kfd_vmfault_fast_path(struct amdgpu_device *adev, struct amdgpu_iv_entr bool retry_fault); void kgd2kfd_lock_kfd(void); void kgd2kfd_teardown_processes(struct amdgpu_device *adev); +int kgd2kfd_reset_mes_queue(struct kfd_dev *kfd, uint32_t node_id, + int queue_type, int pipe, int queue, + unsigned int db); #else static inline int kgd2kfd_init(void) @@ -576,5 +589,12 @@ static inline void kgd2kfd_teardown_processes(struct amdgpu_device *adev) { } +static inline int kgd2kfd_reset_mes_queue(struct kfd_dev *kfd, uint32_t node_id, + int queue_type, int pipe, int queue, + unsigned int db) +{ + return 0; +} + #endif #endif /* AMDGPU_AMDKFD_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c index 6ed399163547..bc079b95fc52 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gc_9_4_3.c @@ -530,6 +530,66 @@ static uint32_t kgd_v9_4_3_ptl_ctrl(struct amdgpu_device *adev, ptl_state, fmt1, fmt2); } +static int kgd_gfx_v9_4_3_hqd_sdma_get_counter(struct amdgpu_device *adev, + void *mqd, uint32_t num_sdma_queues_per_eng, + uint64_t *val) +{ + struct v9_sdma_mqd *m = get_sdma_mqd(mqd); + uint32_t sdma_rlc_reg_offset = 0; + uint32_t sdma_rlc_rb_cntl; + uint32_t engine_id, queue_id; + uint32_t engines = adev->sdma.num_instances; + uint32_t sdma_rlcx_rb_base, sdma_rlcx_rb_base_hi; + bool found = false; + + if (!m) + return -EINVAL; + + if (((amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 3) || + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 4)) && + adev->gfx.mec_fw_version < 194) || + (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 5, 0) && + adev->gfx.mec_fw_version < 44)) { + pr_warn_once("MEC FW doesn't support SDMA counter!\n"); + return -EOPNOTSUPP; + } + + /* SDMA doesn't support over-subscription, there must be + * a HQD associated with a MQD, so found must be true in + * the finding loop. + */ + for (engine_id = 0; engine_id < engines && !found; engine_id++) { + for (queue_id = 0; queue_id < num_sdma_queues_per_eng; queue_id++) { + sdma_rlc_reg_offset = get_sdma_rlc_reg_offset(adev, + engine_id, queue_id); + sdma_rlcx_rb_base = RREG32(sdma_rlc_reg_offset + + regSDMA_RLC0_RB_BASE); + sdma_rlcx_rb_base_hi = RREG32(sdma_rlc_reg_offset + + regSDMA_RLC0_RB_BASE_HI); + + if (m->sdmax_rlcx_rb_base == sdma_rlcx_rb_base && + m->sdmax_rlcx_rb_base_hi == sdma_rlcx_rb_base_hi) { + found = true; + break; + } + } + } + + sdma_rlc_rb_cntl = RREG32(sdma_rlc_reg_offset + regSDMA_RLC0_RB_CNTL); + + /* Read sdma activity counter from utilization register + * if hw queue is enabled, otherwise read from MQD. + */ + if (sdma_rlc_rb_cntl & SDMA_RLC0_RB_CNTL__RB_ENABLE_MASK) + *val = (uint64_t)RREG32(sdma_rlc_reg_offset + regSDMA_RLC0_UTILIZATION_HI) << 32 | + RREG32(sdma_rlc_reg_offset + regSDMA_RLC0_UTILIZATION_LO); + else + *val = (uint64_t)m->sdmax_rlcx_utilization_hi << 32 | + m->sdmax_rlcx_utilization_lo; + + return 0; +} + const struct kfd2kgd_calls gc_9_4_3_kfd2kgd = { .program_sh_mem_settings = kgd_gfx_v9_program_sh_mem_settings, .set_pasid_vmid_mapping = kgd_gfx_v9_4_3_set_pasid_vmid_mapping, @@ -566,5 +626,6 @@ const struct kfd2kgd_calls gc_9_4_3_kfd2kgd = { .hqd_get_pq_addr = kgd_gfx_v9_hqd_get_pq_addr, .hqd_reset = kgd_gfx_v9_hqd_reset, .hqd_sdma_get_doorbell = kgd_gfx_v9_4_3_hqd_sdma_get_doorbell, - .ptl_ctrl = kgd_v9_4_3_ptl_ctrl + .ptl_ctrl = kgd_v9_4_3_ptl_ctrl, + .hqd_sdma_get_counter = kgd_gfx_v9_4_3_hqd_sdma_get_counter }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 35fe2c974699..20831dbebc31 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -2271,11 +2271,14 @@ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo return ret; } -/** amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel() - Map a GTT BO for kernel CPU access +/** amdgpu_amdkfd_gpuvm_map_bo_to_kernel() - Map GTT or VRAM BO for kernel CPU access * * @mem: Buffer object to be mapped for CPU access * @kptr[out]: pointer in kernel CPU address space * @size[out]: size of the buffer + * @domain[IN]: domain for pinning (AMDGPU_GEM_DOMAIN_GTT, AMDGPU_GEM_DOMAIN_VRAM, + * or their combination to let the driver choose). CPU visibility is + * automatically enforced by amdgpu_bo_pin() * * Pins the BO and maps it for kernel CPU access. The eviction fence is removed * from the BO, since pinned BOs cannot be evicted. The bo must remain on the @@ -2284,8 +2287,8 @@ int amdgpu_amdkfd_map_gtt_bo_to_gart(struct amdgpu_bo *bo, struct amdgpu_bo **bo * * Return: 0 on success, error code on failure */ -int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, - void **kptr, uint64_t *size) +int amdgpu_amdkfd_gpuvm_map_bo_to_kernel(struct kgd_mem *mem, void **kptr, + u64 *size, u32 domain) { int ret; struct amdgpu_bo *bo = mem->bo; @@ -2295,6 +2298,11 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, return -EINVAL; } + if (!(domain & (AMDGPU_GEM_DOMAIN_GTT | AMDGPU_GEM_DOMAIN_VRAM))) { + pr_debug("Invalid domain 0x%x for kernel mapping\n", domain); + return -EINVAL; + } + mutex_lock(&mem->process_info->lock); ret = amdgpu_bo_reserve(bo, true); @@ -2303,7 +2311,7 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, goto bo_reserve_failed; } - ret = amdgpu_bo_pin(bo, AMDGPU_GEM_DOMAIN_GTT); + ret = amdgpu_bo_pin(bo, domain); if (ret) { pr_err("Failed to pin bo. ret %d\n", ret); goto pin_failed; @@ -2336,7 +2344,7 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, return ret; } -/** amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel() - Unmap a GTT BO for kernel CPU access +/** amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel() - Unmap GTT or VRAM BO for kernel CPU access * * @mem: Buffer object to be unmapped for CPU access * @@ -2344,7 +2352,7 @@ int amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(struct kgd_mem *mem, * eviction fence, so this function should only be used for cleanup before the * BO is destroyed. */ -void amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(struct kgd_mem *mem) +void amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(struct kgd_mem *mem) { struct amdgpu_bo *bo = mem->bo; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index acd22bff1882..27c0dc8f6137 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -1923,7 +1923,7 @@ int amdgpu_atombios_init(struct amdgpu_device *adev) atom_card_info->pll_read = cail_pll_read; atom_card_info->pll_write = cail_pll_write; - adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios); + adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios, adev->bios_size); if (!adev->mode_info.atom_context) { amdgpu_atombios_fini(adev); return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 3893e6fc2f03..e2a4644896ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -89,6 +89,15 @@ bool amdgpu_is_atpx_hybrid(void) return amdgpu_atpx_priv.atpx.is_hybrid; } +static bool amdgpu_atpx_buffer_validate(const union acpi_object *obj, + size_t min_size) +{ + return obj && obj->type == ACPI_TYPE_BUFFER && + obj->buffer.length >= sizeof(u16) && + obj->buffer.length >= *(u16 *)obj->buffer.pointer && + *(u16 *)obj->buffer.pointer >= min_size; +} + /** * amdgpu_atpx_call - call an ATPX method * @@ -179,15 +188,15 @@ static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx) if (!info) return -EIO; - memset(&output, 0, sizeof(output)); - - size = *(u16 *) info->buffer.pointer; - if (size < 10) { - pr_err("ATPX buffer is too small: %zu\n", size); + if (!amdgpu_atpx_buffer_validate(info, sizeof(output))) { + pr_err("Invalid ATPX GET_PX_PARAMETERS response\n"); kfree(info); return -EINVAL; } - size = min(sizeof(output), size); + + memset(&output, 0, sizeof(output)); + + size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer); memcpy(&output, info->buffer.pointer, size); @@ -258,15 +267,15 @@ static int amdgpu_atpx_verify_interface(struct amdgpu_atpx *atpx) if (!info) return -EIO; - memset(&output, 0, sizeof(output)); - - size = *(u16 *) info->buffer.pointer; - if (size < 8) { - pr_err("ATPX buffer is too small: %zu\n", size); + if (!amdgpu_atpx_buffer_validate(info, sizeof(output))) { + pr_err("Invalid ATPX VERIFY_INTERFACE response\n"); err = -EINVAL; goto out; } - size = min(sizeof(output), size); + + memset(&output, 0, sizeof(output)); + + size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer); memcpy(&output, info->buffer.pointer, size); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index aa039e148a5e..3ebdd792feec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -296,8 +296,14 @@ static int amdgpu_atrm_call(acpi_handle atrm_handle, uint8_t *bios, } obj = (union acpi_object *)buffer.pointer; - memcpy(bios+offset, obj->buffer.pointer, obj->buffer.length); - len = obj->buffer.length; + if (!obj || obj->type != ACPI_TYPE_BUFFER) { + DRM_ERROR("ATRM returned an invalid object\n"); + kfree(buffer.pointer); + return -EINVAL; + } + + len = min_t(size_t, obj->buffer.length, len); + memcpy(bios+offset, obj->buffer.pointer, len); kfree(buffer.pointer); return len; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 43864df8af04..ce1d08f112a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -38,14 +38,6 @@ #define AMDGPU_BO_LIST_NUM_BUCKETS (AMDGPU_BO_LIST_MAX_PRIORITY + 1) #define AMDGPU_BO_LIST_MAX_ENTRIES (128 * 1024) -static void amdgpu_bo_list_free_rcu(struct rcu_head *rcu) -{ - struct amdgpu_bo_list *list = container_of(rcu, struct amdgpu_bo_list, - rhead); - mutex_destroy(&list->bo_list_mutex); - kvfree(list); -} - static void amdgpu_bo_list_free(struct kref *ref) { struct amdgpu_bo_list *list = container_of(ref, struct amdgpu_bo_list, @@ -54,7 +46,8 @@ static void amdgpu_bo_list_free(struct kref *ref) amdgpu_bo_list_for_each_entry(e, list) amdgpu_bo_unref(&e->bo); - call_rcu(&list->rhead, amdgpu_bo_list_free_rcu); + + kvfree(list); } static int amdgpu_bo_list_entry_cmp(const void *_a, const void *_b) @@ -66,9 +59,9 @@ static int amdgpu_bo_list_entry_cmp(const void *_a, const void *_b) return (int)a->priority - (int)b->priority; } -int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, - struct drm_amdgpu_bo_list_entry *info, - size_t num_entries, struct amdgpu_bo_list **result) +struct amdgpu_bo_list * +amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, + struct drm_amdgpu_bo_list_entry *info, size_t num_entries) { unsigned last_entry = 0, first_userptr = num_entries; struct amdgpu_bo_list_entry *array; @@ -79,7 +72,7 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, list = kvzalloc_flex(*list, entries, num_entries); if (!list) - return -ENOMEM; + return ERR_PTR(-ENOMEM); kref_init(&list->refcount); @@ -134,9 +127,7 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, trace_amdgpu_cs_bo_status(list->num_entries, total_size); - mutex_init(&list->bo_list_mutex); - *result = list; - return 0; + return list; error_free: for (i = 0; i < last_entry; ++i) @@ -144,150 +135,125 @@ int amdgpu_bo_list_create(struct amdgpu_device *adev, struct drm_file *filp, for (i = first_userptr; i < num_entries; ++i) amdgpu_bo_unref(&array[i].bo); kvfree(list); - return r; + return ERR_PTR(r); } -static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id) +struct amdgpu_bo_list *amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, u32 id) { struct amdgpu_bo_list *list; - mutex_lock(&fpriv->bo_list_lock); - list = idr_remove(&fpriv->bo_list_handles, id); - mutex_unlock(&fpriv->bo_list_lock); + xa_lock(&fpriv->bo_list_handles); + list = xa_load(&fpriv->bo_list_handles, id); if (list) - kref_put(&list->refcount, amdgpu_bo_list_free); -} + kref_get(&list->refcount); + else + list = ERR_PTR(-ENOENT); + xa_unlock(&fpriv->bo_list_handles); -int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, - struct amdgpu_bo_list **result) -{ - rcu_read_lock(); - *result = idr_find(&fpriv->bo_list_handles, id); - - if (*result && kref_get_unless_zero(&(*result)->refcount)) { - rcu_read_unlock(); - return 0; - } - - rcu_read_unlock(); - *result = NULL; - return -ENOENT; + return list; } void amdgpu_bo_list_put(struct amdgpu_bo_list *list) { - kref_put(&list->refcount, amdgpu_bo_list_free); + if (list) + kref_put(&list->refcount, amdgpu_bo_list_free); } -int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, - struct drm_amdgpu_bo_list_entry **info_param) +struct drm_amdgpu_bo_list_entry * +amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in) { - const uint32_t info_size = sizeof(struct drm_amdgpu_bo_list_entry); const void __user *uptr = u64_to_user_ptr(in->bo_info_ptr); - const uint32_t bo_info_size = in->bo_info_size; const uint32_t bo_number = in->bo_number; - struct drm_amdgpu_bo_list_entry *info; if (bo_number > AMDGPU_BO_LIST_MAX_ENTRIES) - return -EINVAL; + return ERR_PTR(-EINVAL); - /* copy the handle array from userspace to a kernel buffer */ - if (likely(info_size == bo_info_size)) { - info = vmemdup_array_user(uptr, bo_number, info_size); - if (IS_ERR(info)) - return PTR_ERR(info); - } else { - const uint32_t bytes = min(bo_info_size, info_size); - unsigned i; + if (in->bo_info_size != sizeof(struct drm_amdgpu_bo_list_entry)) + return ERR_PTR(-EINVAL); - info = kvmalloc_array(bo_number, info_size, GFP_KERNEL); - if (!info) - return -ENOMEM; - - memset(info, 0, bo_number * info_size); - for (i = 0; i < bo_number; ++i, uptr += bo_info_size) { - if (copy_from_user(&info[i], uptr, bytes)) { - kvfree(info); - return -EFAULT; - } - } - } - - *info_param = info; - return 0; + return vmemdup_array_user(uptr, bo_number, + sizeof(struct drm_amdgpu_bo_list_entry)); } int amdgpu_bo_list_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { - struct amdgpu_device *adev = drm_to_adev(dev); struct amdgpu_fpriv *fpriv = filp->driver_priv; + struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_bo_list *list, *prev, *curr; union drm_amdgpu_bo_list *args = data; uint32_t handle = args->in.list_handle; - struct drm_amdgpu_bo_list_entry *info = NULL; - struct amdgpu_bo_list *list, *old; + struct drm_amdgpu_bo_list_entry *info; int r; - r = amdgpu_bo_create_list_entry_array(&args->in, &info); - if (r) - return r; - switch (args->in.operation) { case AMDGPU_BO_LIST_OP_CREATE: - r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number, - &list); - if (r) - goto error_free; + case AMDGPU_BO_LIST_OP_UPDATE: + info = amdgpu_bo_create_list_entry_array(&args->in); + if (IS_ERR(info)) + return PTR_ERR(info); - mutex_lock(&fpriv->bo_list_lock); - r = idr_alloc(&fpriv->bo_list_handles, list, 1, 0, GFP_KERNEL); - mutex_unlock(&fpriv->bo_list_lock); - if (r < 0) { - goto error_put_list; - } + list = amdgpu_bo_list_create(adev, filp, info, + args->in.bo_number); + kvfree(info); + if (IS_ERR(list)) + return PTR_ERR(list); - handle = r; break; case AMDGPU_BO_LIST_OP_DESTROY: - amdgpu_bo_list_destroy(fpriv, handle); + list = xa_erase(&fpriv->bo_list_handles, handle); + amdgpu_bo_list_put(list); handle = 0; - break; - case AMDGPU_BO_LIST_OP_UPDATE: - r = amdgpu_bo_list_create(adev, filp, info, args->in.bo_number, - &list); - if (r) - goto error_free; - - mutex_lock(&fpriv->bo_list_lock); - old = idr_replace(&fpriv->bo_list_handles, list, handle); - mutex_unlock(&fpriv->bo_list_lock); - - if (IS_ERR(old)) { - r = PTR_ERR(old); - goto error_put_list; - } - - amdgpu_bo_list_put(old); break; default: - r = -EINVAL; - goto error_free; + return -EINVAL; + }; + + switch (args->in.operation) { + case AMDGPU_BO_LIST_OP_CREATE: + r = xa_alloc(&fpriv->bo_list_handles, &handle, list, + xa_limit_32b, GFP_KERNEL); + if (r) + goto error_put_list; + + break; + + case AMDGPU_BO_LIST_OP_UPDATE: + curr = xa_load(&fpriv->bo_list_handles, handle); + if (!curr) { + r = -ENOENT; + goto error_put_list; + } + + prev = xa_cmpxchg(&fpriv->bo_list_handles, handle, curr, list, + GFP_KERNEL); + if (xa_is_err(prev)) { + r = xa_err(prev); + goto error_put_list; + } else if (prev != curr) { + r = -ENOENT; + goto error_put_list; + } + + amdgpu_bo_list_put(curr); + break; + + case AMDGPU_BO_LIST_OP_DESTROY: + default: + /* Handled above. */ + break; } memset(args, 0, sizeof(*args)); args->out.list_handle = handle; - kvfree(info); return 0; error_put_list: amdgpu_bo_list_put(list); - -error_free: - kvfree(info); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h index 2b5e7c46a39d..bde912150824 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.h @@ -43,7 +43,6 @@ struct amdgpu_bo_list_entry { }; struct amdgpu_bo_list { - struct rcu_head rhead; struct kref refcount; struct amdgpu_bo *gds_obj; struct amdgpu_bo *gws_obj; @@ -51,24 +50,19 @@ struct amdgpu_bo_list { unsigned first_userptr; unsigned num_entries; - /* Protect access during command submission. - */ - struct mutex bo_list_mutex; - struct amdgpu_bo_list_entry entries[] __counted_by(num_entries); }; -int amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id, - struct amdgpu_bo_list **result); +struct amdgpu_bo_list *amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, u32 id); void amdgpu_bo_list_put(struct amdgpu_bo_list *list); -int amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in, - struct drm_amdgpu_bo_list_entry **info_param); +struct drm_amdgpu_bo_list_entry * +amdgpu_bo_create_list_entry_array(struct drm_amdgpu_bo_list_in *in); -int amdgpu_bo_list_create(struct amdgpu_device *adev, - struct drm_file *filp, - struct drm_amdgpu_bo_list_entry *info, - size_t num_entries, - struct amdgpu_bo_list **list); +struct amdgpu_bo_list * +amdgpu_bo_list_create(struct amdgpu_device *adev, + struct drm_file *filp, + struct drm_amdgpu_bo_list_entry *info, + size_t num_entries); #define amdgpu_bo_list_for_each_entry(e, list) \ for (e = list->entries; \ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c index d5e59c24d907..6fb129025761 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.c @@ -289,40 +289,6 @@ struct cper_hdr *amdgpu_cper_alloc_entry(struct amdgpu_device *adev, return hdr; } -int amdgpu_cper_generate_ue_record(struct amdgpu_device *adev, - struct aca_bank *bank) -{ - struct cper_hdr *fatal = NULL; - struct cper_sec_crashdump_reg_data reg_data = { 0 }; - struct amdgpu_ring *ring = &adev->cper.ring_buf; - int ret; - - fatal = amdgpu_cper_alloc_entry(adev, AMDGPU_CPER_TYPE_FATAL, 1); - if (!fatal) { - dev_err(adev->dev, "fail to alloc cper entry for ue record\n"); - return -ENOMEM; - } - - reg_data.status_lo = lower_32_bits(bank->regs[ACA_REG_IDX_STATUS]); - reg_data.status_hi = upper_32_bits(bank->regs[ACA_REG_IDX_STATUS]); - reg_data.addr_lo = lower_32_bits(bank->regs[ACA_REG_IDX_ADDR]); - reg_data.addr_hi = upper_32_bits(bank->regs[ACA_REG_IDX_ADDR]); - reg_data.ipid_lo = lower_32_bits(bank->regs[ACA_REG_IDX_IPID]); - reg_data.ipid_hi = upper_32_bits(bank->regs[ACA_REG_IDX_IPID]); - reg_data.synd_lo = lower_32_bits(bank->regs[ACA_REG_IDX_SYND]); - reg_data.synd_hi = upper_32_bits(bank->regs[ACA_REG_IDX_SYND]); - - amdgpu_cper_entry_fill_hdr(adev, fatal, AMDGPU_CPER_TYPE_FATAL, CPER_SEV_FATAL_UNCORRECTED); - ret = amdgpu_cper_entry_fill_fatal_section(adev, fatal, 0, reg_data); - if (ret) - return ret; - - amdgpu_cper_ring_write(ring, fatal, fatal->record_length); - kfree(fatal); - - return 0; -} - int amdgpu_cper_generate_bp_threshold_record(struct amdgpu_device *adev) { struct cper_hdr *bp_threshold = NULL; @@ -348,83 +314,6 @@ int amdgpu_cper_generate_bp_threshold_record(struct amdgpu_device *adev) return 0; } -static enum cper_error_severity amdgpu_aca_err_type_to_cper_sev(struct amdgpu_device *adev, - enum aca_error_type aca_err_type) -{ - switch (aca_err_type) { - case ACA_ERROR_TYPE_UE: - return CPER_SEV_FATAL_UNCORRECTED; - case ACA_ERROR_TYPE_CE: - return CPER_SEV_NON_FATAL_CORRECTED; - case ACA_ERROR_TYPE_DEFERRED: - return CPER_SEV_NON_FATAL_UNCORRECTED; - default: - dev_err(adev->dev, "Unknown ACA error type!\n"); - return CPER_SEV_FATAL_UNCORRECTED; - } -} - -int amdgpu_cper_generate_ce_records(struct amdgpu_device *adev, - struct aca_banks *banks, - uint16_t bank_count) -{ - struct cper_hdr *corrected = NULL; - enum cper_error_severity sev = CPER_SEV_NON_FATAL_CORRECTED; - struct amdgpu_ring *ring = &adev->cper.ring_buf; - uint32_t reg_data[CPER_ACA_REG_COUNT] = { 0 }; - struct aca_bank_node *node; - struct aca_bank *bank; - uint32_t i = 0; - int ret; - - corrected = amdgpu_cper_alloc_entry(adev, AMDGPU_CPER_TYPE_RUNTIME, bank_count); - if (!corrected) { - dev_err(adev->dev, "fail to allocate cper entry for ce records\n"); - return -ENOMEM; - } - - /* Raise severity if any DE is detected in the ACA bank list */ - list_for_each_entry(node, &banks->list, node) { - bank = &node->bank; - if (bank->aca_err_type == ACA_ERROR_TYPE_DEFERRED) { - sev = CPER_SEV_NON_FATAL_UNCORRECTED; - break; - } - } - - amdgpu_cper_entry_fill_hdr(adev, corrected, AMDGPU_CPER_TYPE_RUNTIME, sev); - - /* Combine CE and DE in cper record */ - list_for_each_entry(node, &banks->list, node) { - bank = &node->bank; - reg_data[CPER_ACA_REG_CTL_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_CTL]); - reg_data[CPER_ACA_REG_CTL_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_CTL]); - reg_data[CPER_ACA_REG_STATUS_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_STATUS]); - reg_data[CPER_ACA_REG_STATUS_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_STATUS]); - reg_data[CPER_ACA_REG_ADDR_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_ADDR]); - reg_data[CPER_ACA_REG_ADDR_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_ADDR]); - reg_data[CPER_ACA_REG_MISC0_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_MISC0]); - reg_data[CPER_ACA_REG_MISC0_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_MISC0]); - reg_data[CPER_ACA_REG_CONFIG_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_CONFIG]); - reg_data[CPER_ACA_REG_CONFIG_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_CONFIG]); - reg_data[CPER_ACA_REG_IPID_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_IPID]); - reg_data[CPER_ACA_REG_IPID_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_IPID]); - reg_data[CPER_ACA_REG_SYND_LO] = lower_32_bits(bank->regs[ACA_REG_IDX_SYND]); - reg_data[CPER_ACA_REG_SYND_HI] = upper_32_bits(bank->regs[ACA_REG_IDX_SYND]); - - ret = amdgpu_cper_entry_fill_runtime_section(adev, corrected, i++, - amdgpu_aca_err_type_to_cper_sev(adev, bank->aca_err_type), - reg_data, CPER_ACA_REG_COUNT); - if (ret) - return ret; - } - - amdgpu_cper_ring_write(ring, corrected, corrected->record_length); - kfree(corrected); - - return 0; -} - static bool amdgpu_cper_is_hdr(struct amdgpu_ring *ring, u64 pos) { char signature[CPER_SIGNATURE_SZ]; @@ -592,8 +481,7 @@ int amdgpu_cper_init(struct amdgpu_device *adev) if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_ras_cper_en(adev)) return 0; - else if (!amdgpu_sriov_vf(adev) && !amdgpu_uniras_enabled(adev) && - !amdgpu_aca_is_enabled(adev)) + else if (!amdgpu_sriov_vf(adev) && !amdgpu_uniras_enabled(adev)) return 0; r = amdgpu_cper_ring_init(adev); @@ -612,7 +500,7 @@ int amdgpu_cper_init(struct amdgpu_device *adev) int amdgpu_cper_fini(struct amdgpu_device *adev) { - if (!amdgpu_aca_is_enabled(adev) && !amdgpu_sriov_ras_cper_en(adev)) + if (amdgpu_sriov_vf(adev)) return 0; adev->cper.enabled = false; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.h index 353421807387..d12c98077d9d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cper.h @@ -26,7 +26,6 @@ #define __AMDGPU_CPER_H__ #include "amd_cper.h" -#include "amdgpu_aca.h" #define CPER_MAX_ALLOWED_COUNT 0x1000 #define CPER_MAX_RING_SIZE 0X100000 @@ -88,13 +87,6 @@ int amdgpu_cper_entry_fill_bad_page_threshold_section(struct amdgpu_device *adev struct cper_hdr *amdgpu_cper_alloc_entry(struct amdgpu_device *adev, enum amdgpu_cper_type type, uint16_t section_count); -/* UE must be encoded into separated cper entries, 1 UE 1 cper */ -int amdgpu_cper_generate_ue_record(struct amdgpu_device *adev, - struct aca_bank *bank); -/* CEs and DEs are combined into 1 cper entry */ -int amdgpu_cper_generate_ce_records(struct amdgpu_device *adev, - struct aca_banks *banks, - uint16_t bank_count); /* Bad page threshold is encoded into separated cper entry */ int amdgpu_cper_generate_bp_threshold_record(struct amdgpu_device *adev); void amdgpu_cper_ring_write(struct amdgpu_ring *ring, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index c2e6495a28bc..d777375e5350 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -140,24 +140,19 @@ static int amdgpu_cs_p1_bo_handles(struct amdgpu_cs_parser *p, struct drm_amdgpu_bo_list_in *data) { struct drm_amdgpu_bo_list_entry *info; - int r; + struct amdgpu_bo_list *list; - r = amdgpu_bo_create_list_entry_array(data, &info); - if (r) - return r; - - r = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number, - &p->bo_list); - if (r) - goto error_free; + info = amdgpu_bo_create_list_entry_array(data); + if (IS_ERR(info)) + return PTR_ERR(info); + list = amdgpu_bo_list_create(p->adev, p->filp, info, data->bo_number); kvfree(info); + if (IS_ERR(list)) + return PTR_ERR(list); + + p->bo_list = list; return 0; - -error_free: - kvfree(info); - - return r; } /* Copy the data from userspace and go over it the first time */ @@ -846,6 +841,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, { struct amdgpu_fpriv *fpriv = p->filp->driver_priv; struct ttm_operation_ctx ctx = { true, false }; + struct amdgpu_bo_list *list = NULL; struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_bo_list_entry *e; struct drm_gem_object *obj; @@ -857,25 +853,24 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, if (p->bo_list) return -EINVAL; - r = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle, - &p->bo_list); - if (r) - return r; + list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); } else if (!p->bo_list) { /* Create a empty bo_list when no handle is provided */ - r = amdgpu_bo_list_create(p->adev, p->filp, NULL, 0, - &p->bo_list); - if (r) - return r; + list = amdgpu_bo_list_create(p->adev, p->filp, NULL, 0); } - mutex_lock(&p->bo_list->bo_list_mutex); + if (IS_ERR(list)) + return PTR_ERR(list); + else if (list) + p->bo_list = list; + else + list = p->bo_list; /* Get userptr backing pages. If pages are updated after registered * in amdgpu_gem_userptr_ioctl(), amdgpu_cs_list_validate() will do * amdgpu_ttm_backend_bind() to flush and invalidate new pages */ - amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + amdgpu_bo_list_for_each_userptr_entry(e, list) { bool userpage_invalidated = false; struct amdgpu_bo *bo = e->bo; @@ -905,7 +900,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, if (unlikely(r)) goto out_free_user_pages; - amdgpu_bo_list_for_each_entry(e, p->bo_list) { + amdgpu_bo_list_for_each_entry(e, list) { r = drm_exec_prepare_obj(&p->exec, &e->bo->tbo.base, TTM_NUM_MOVE_FENCES + p->gang_size); drm_exec_retry_on_contention(&p->exec); @@ -924,7 +919,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, } } - amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + amdgpu_bo_list_for_each_userptr_entry(e, list) { struct mm_struct *usermm; usermm = amdgpu_ttm_tt_get_usermm(e->bo->tbo.ttm); @@ -977,17 +972,15 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, p->bytes_moved_vis); for (i = 0; i < p->gang_size; ++i) - amdgpu_job_set_resources(p->jobs[i], p->bo_list->gds_obj, - p->bo_list->gws_obj, - p->bo_list->oa_obj); + amdgpu_job_set_resources(p->jobs[i], list->gds_obj, + list->gws_obj, list->oa_obj); return 0; out_free_user_pages: - amdgpu_bo_list_for_each_userptr_entry(e, p->bo_list) { + amdgpu_bo_list_for_each_userptr_entry(e, list) { amdgpu_hmm_range_free(e->range); e->range = NULL; } - mutex_unlock(&p->bo_list->bo_list_mutex); return r; } @@ -1322,7 +1315,7 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, e->range = NULL; } - if (r || !list_empty(&vm->individual.moved)) { + if (r || !list_empty(&vm->individual.needs_update)) { r = -EAGAIN; mutex_unlock(&p->adev->notifier_lock); return r; @@ -1371,7 +1364,6 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, amdgpu_vm_move_to_lru_tail(p->adev, &fpriv->vm); mutex_unlock(&p->adev->notifier_lock); - mutex_unlock(&p->bo_list->bo_list_mutex); return 0; } @@ -1443,28 +1435,25 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) r = amdgpu_cs_patch_jobs(&parser); if (r) - goto error_backoff; + goto error_fini; r = amdgpu_cs_vm_handling(&parser); if (r) - goto error_backoff; + goto error_fini; r = amdgpu_cs_sync_rings(&parser); if (r) - goto error_backoff; + goto error_fini; trace_amdgpu_cs_ibs(&parser); r = amdgpu_cs_submit(&parser, data); if (r) - goto error_backoff; + goto error_fini; amdgpu_cs_parser_fini(&parser); return 0; -error_backoff: - mutex_unlock(&parser.bo_list->bo_list_mutex); - error_fini: amdgpu_cs_parser_fini(&parser); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index ce35b415093d..d53259a5b82f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -283,6 +283,8 @@ static ktime_t amdgpu_ctx_fini_entity(struct amdgpu_device *adev, if (!entity) return res; + drm_sched_entity_destroy(&entity->entity); + for (i = 0; i < amdgpu_sched_jobs; ++i) { res = ktime_add(res, amdgpu_ctx_fence_time(entity->fences[i])); dma_fence_put(entity->fences[i]); @@ -294,32 +296,20 @@ static ktime_t amdgpu_ctx_fini_entity(struct amdgpu_device *adev, return res; } -static int amdgpu_ctx_get_stable_pstate(struct amdgpu_ctx *ctx, - u32 *stable_pstate) +static u32 amdgpu_get_stable_pstate(struct amdgpu_device *adev) { - struct amdgpu_device *adev = ctx->mgr->adev; - enum amd_dpm_forced_level current_level; - - current_level = amdgpu_dpm_get_performance_level(adev); - - switch (current_level) { + switch (amdgpu_dpm_get_performance_level(adev)) { case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: - *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_STANDARD; - break; + return AMDGPU_CTX_STABLE_PSTATE_STANDARD; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: - *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK; - break; + return AMDGPU_CTX_STABLE_PSTATE_MIN_SCLK; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: - *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK; - break; + return AMDGPU_CTX_STABLE_PSTATE_MIN_MCLK; case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: - *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_PEAK; - break; + return AMDGPU_CTX_STABLE_PSTATE_PEAK; default: - *stable_pstate = AMDGPU_CTX_STABLE_PSTATE_NONE; - break; + return AMDGPU_CTX_STABLE_PSTATE_NONE; } - return 0; } static int amdgpu_ctx_init(struct amdgpu_ctx_mgr *mgr, int32_t priority, @@ -383,9 +373,9 @@ static int __amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx, if (current_ctx && current_ctx != ctx) return -EBUSY; - r = amdgpu_ctx_get_stable_pstate(ctx, ¤t_stable_pstate); - if (r || current_stable_pstate == stable_pstate) - return r; + current_stable_pstate = amdgpu_get_stable_pstate(adev); + if (current_stable_pstate == stable_pstate) + return 0; r = amdgpu_dpm_force_performance_level(adev, level); if (r) @@ -416,7 +406,7 @@ static int amdgpu_ctx_set_stable_pstate(struct amdgpu_ctx *ctx, return r; } -static void amdgpu_ctx_fini(struct kref *ref) +void amdgpu_ctx_fini(struct kref *ref) { struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount); struct amdgpu_ctx_mgr *mgr = ctx->mgr; @@ -504,53 +494,26 @@ static int amdgpu_ctx_alloc(struct amdgpu_device *adev, if (!ctx) return -ENOMEM; - mutex_lock(&mgr->lock); - r = idr_alloc(&mgr->ctx_handles, ctx, 1, AMDGPU_VM_MAX_NUM_CTX, GFP_KERNEL); - if (r < 0) { - mutex_unlock(&mgr->lock); + r = amdgpu_ctx_init(mgr, priority, filp, ctx); + if (r) { kfree(ctx); return r; } - *id = (uint32_t)r; - r = amdgpu_ctx_init(mgr, priority, filp, ctx); - if (r) { - idr_remove(&mgr->ctx_handles, *id); - *id = 0; - kfree(ctx); - } - mutex_unlock(&mgr->lock); + r = xa_alloc(&mgr->ctx_handles, id, ctx, xa_limit_32b, GFP_KERNEL); + if (r) + amdgpu_ctx_put(ctx); + return r; } -static void amdgpu_ctx_do_release(struct kref *ref) -{ - struct amdgpu_ctx *ctx; - u32 i, j; - - ctx = container_of(ref, struct amdgpu_ctx, refcount); - for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { - for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { - if (!ctx->entities[i][j]) - continue; - - drm_sched_entity_destroy(&ctx->entities[i][j]->entity); - } - } - - amdgpu_ctx_fini(ref); -} - static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id) { - struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr; struct amdgpu_ctx *ctx; - mutex_lock(&mgr->lock); - ctx = idr_remove(&mgr->ctx_handles, id); - if (ctx) - kref_put(&ctx->refcount, amdgpu_ctx_do_release); - mutex_unlock(&mgr->lock); + ctx = xa_erase(&fpriv->ctx_mgr.ctx_handles, id); + amdgpu_ctx_put(ctx); + return ctx ? 0 : -EINVAL; } @@ -559,20 +522,12 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev, union drm_amdgpu_ctx_out *out) { struct amdgpu_ctx *ctx; - struct amdgpu_ctx_mgr *mgr; unsigned reset_counter; - if (!fpriv) + ctx = amdgpu_ctx_get(fpriv, id); + if (!ctx) return -EINVAL; - mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); - if (!ctx) { - mutex_unlock(&mgr->lock); - return -EINVAL; - } - /* TODO: these two are always zero */ out->state.flags = 0x0; out->state.hangs = 0x0; @@ -586,7 +541,8 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev, out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET; ctx->reset_counter_query = reset_counter; - mutex_unlock(&mgr->lock); + amdgpu_ctx_put(ctx); + return 0; } @@ -619,19 +575,11 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev, { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct amdgpu_ctx *ctx; - struct amdgpu_ctx_mgr *mgr; - if (!fpriv) + ctx = amdgpu_ctx_get(fpriv, id); + if (!ctx) return -EINVAL; - mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); - if (!ctx) { - mutex_unlock(&mgr->lock); - return -EINVAL; - } - out->state.flags = 0x0; out->state.hangs = 0x0; @@ -671,7 +619,8 @@ static int amdgpu_ctx_query2(struct amdgpu_device *adev, msecs_to_jiffies(AMDGPU_RAS_COUNTE_DELAY_MS)); } - mutex_unlock(&mgr->lock); + amdgpu_ctx_put(ctx); + return 0; } @@ -680,26 +629,26 @@ static int amdgpu_ctx_stable_pstate(struct amdgpu_device *adev, bool set, u32 *stable_pstate) { struct amdgpu_ctx *ctx; - struct amdgpu_ctx_mgr *mgr; - int r; + int r = 0; - if (!fpriv) + ctx = amdgpu_ctx_get(fpriv, id); + if (!ctx) return -EINVAL; - mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); - if (!ctx) { - mutex_unlock(&mgr->lock); - return -EINVAL; - } + /* + * The get path is odd in this uapi - it will check whether the context + * id exist, but otherwise does nothing with it. In other words, the + * uapi has historically been implemented as being able to query the + * global device state, as long as the caller supplies a random valid + * context id. + */ if (set) r = amdgpu_ctx_set_stable_pstate(ctx, *stable_pstate); else - r = amdgpu_ctx_get_stable_pstate(ctx, stable_pstate); + *stable_pstate = amdgpu_get_stable_pstate(adev); - mutex_unlock(&mgr->lock); + amdgpu_ctx_put(ctx); return r; } @@ -778,23 +727,14 @@ struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id) mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - ctx = idr_find(&mgr->ctx_handles, id); + xa_lock(&mgr->ctx_handles); + ctx = xa_load(&mgr->ctx_handles, id); if (ctx) kref_get(&ctx->refcount); - mutex_unlock(&mgr->lock); + xa_unlock(&mgr->ctx_handles); return ctx; } -int amdgpu_ctx_put(struct amdgpu_ctx *ctx) -{ - if (ctx == NULL) - return -EINVAL; - - kref_put(&ctx->refcount, amdgpu_ctx_do_release); - return 0; -} - uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct drm_sched_entity *entity, struct dma_fence *fence) @@ -928,8 +868,7 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr, unsigned int i; mgr->adev = adev; - mutex_init(&mgr->lock); - idr_init_base(&mgr->ctx_handles, 1); + xa_init_flags(&mgr->ctx_handles, XA_FLAGS_ALLOC1); for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) atomic64_set(&mgr->time_spend[i], 0); @@ -938,13 +877,13 @@ void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr, long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout) { struct amdgpu_ctx *ctx; - struct idr *idp; - uint32_t id, i, j; + unsigned long id; + int i, j; - idp = &mgr->ctx_handles; - - mutex_lock(&mgr->lock); - idr_for_each_entry(idp, ctx, id) { + xa_lock(&mgr->ctx_handles); + xa_for_each(&mgr->ctx_handles, id, ctx) { + kref_get(&ctx->refcount); + xa_unlock(&mgr->ctx_handles); for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { struct drm_sched_entity *entity; @@ -956,45 +895,21 @@ long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout) timeout = drm_sched_entity_flush(entity, timeout); } } + amdgpu_ctx_put(ctx); + xa_lock(&mgr->ctx_handles); } - mutex_unlock(&mgr->lock); + xa_unlock(&mgr->ctx_handles); return timeout; } -static void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr) -{ - struct amdgpu_ctx *ctx; - struct idr *idp; - uint32_t id, i, j; - - idp = &mgr->ctx_handles; - - idr_for_each_entry(idp, ctx, id) { - if (kref_read(&ctx->refcount) != 1) { - drm_err(adev_to_drm(mgr->adev), "ctx %p is still alive\n", ctx); - continue; - } - - for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) { - for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) { - struct drm_sched_entity *entity; - - if (!ctx->entities[i][j]) - continue; - - entity = &ctx->entities[i][j]->entity; - drm_sched_entity_fini(entity); - } - } - kref_put(&ctx->refcount, amdgpu_ctx_fini); - } -} - void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr) { - amdgpu_ctx_mgr_entity_fini(mgr); - idr_destroy(&mgr->ctx_handles); - mutex_destroy(&mgr->lock); + struct amdgpu_ctx *ctx; + unsigned long id; + + xa_for_each(&mgr->ctx_handles, id, ctx) + amdgpu_ctx_put(ctx); + xa_destroy(&mgr->ctx_handles); } void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, @@ -1002,21 +917,21 @@ void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, { struct amdgpu_ctx *ctx; unsigned int hw_ip, i; - uint32_t id; + unsigned long id; /* * This is a little bit racy because it can be that a ctx or a fence are * destroyed just in the moment we try to account them. But that is ok * since exactly that case is explicitely allowed by the interface. */ - mutex_lock(&mgr->lock); for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { uint64_t ns = atomic64_read(&mgr->time_spend[hw_ip]); usage[hw_ip] = ns_to_ktime(ns); } - idr_for_each_entry(&mgr->ctx_handles, ctx, id) { + xa_lock(&mgr->ctx_handles); + xa_for_each(&mgr->ctx_handles, id, ctx) { for (hw_ip = 0; hw_ip < AMDGPU_HW_IP_NUM; ++hw_ip) { for (i = 0; i < amdgpu_ctx_num_entities[hw_ip]; ++i) { struct amdgpu_ctx_entity *centity; @@ -1030,5 +945,5 @@ void amdgpu_ctx_mgr_usage(struct amdgpu_ctx_mgr *mgr, } } } - mutex_unlock(&mgr->lock); + xa_unlock(&mgr->ctx_handles); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h index e444b2088d40..a4b89eca4169 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.h @@ -25,6 +25,7 @@ #include #include +#include #include "amdgpu_ring.h" @@ -60,16 +61,21 @@ struct amdgpu_ctx { struct amdgpu_ctx_mgr { struct amdgpu_device *adev; - struct mutex lock; - /* protected by lock */ - struct idr ctx_handles; + struct xarray ctx_handles; atomic64_t time_spend[AMDGPU_HW_IP_NUM]; }; extern const unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM]; struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id); -int amdgpu_ctx_put(struct amdgpu_ctx *ctx); + +void amdgpu_ctx_fini(struct kref *kref); + +static inline void amdgpu_ctx_put(struct amdgpu_ctx *ctx) +{ + if (ctx) + kref_put(&ctx->refcount, amdgpu_ctx_fini); +} int amdgpu_ctx_get_entity(struct amdgpu_ctx *ctx, u32 hw_ip, u32 instance, u32 ring, struct drm_sched_entity **entity); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c index 389bad724273..0455c2cd043f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "amdgpu.h" @@ -1739,6 +1740,12 @@ int amdgpu_debugfs_regs_init(struct amdgpu_device *adev) struct dentry *ent, *root = minor->debugfs_root; unsigned int i; + if (security_locked_down(LOCKDOWN_PCI_ACCESS)) { + drm_info(adev_to_drm(adev), + "amdgpu: HW debugfs nodes disabled (kernel lockdown)\n"); + return 0; + } + for (i = 0; i < ARRAY_SIZE(debugfs_regs); i++) { ent = debugfs_create_file(debugfs_regs_names[i], S_IFREG | 0400, root, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c index e77db76b48b8..4fd0df3aa70d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_dev_coredump.c @@ -64,6 +64,7 @@ const char *hw_ip_names[MAX_HWIP] = { [VCN1_HWIP] = "VCN1", [VCE_HWIP] = "VCE", [VPE_HWIP] = "VPE", + [UMSCH_HWIP] = "UMSCH", [DF_HWIP] = "DF", [DCE_HWIP] = "DCE", [OSSSYS_HWIP] = "OSSSYS", diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 211d30f03d25..78c96c7102e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -74,6 +74,7 @@ #include "amdgpu_ras.h" #include "amdgpu_ras_mgr.h" #include "amdgpu_pmu.h" +#include "amdgpu_smu.h" #include "amdgpu_fru_eeprom.h" #include "amdgpu_reset.h" #include "amdgpu_virt.h" @@ -2130,6 +2131,8 @@ static int amdgpu_device_ip_early_init(struct amdgpu_device *adev) adev->cg_flags &= amdgpu_cg_mask; adev->pg_flags &= amdgpu_pg_mask; + amdgpu_smu_early_init(adev); + return 0; } @@ -3677,6 +3680,10 @@ static void amdgpu_device_sys_interface_fini(struct amdgpu_device *adev) amdgpu_pm_sysfs_fini(adev); if (adev->ucode_sysfs_en) amdgpu_ucode_sysfs_fini(adev); + + amdgpu_discovery_sysfs_fini(adev); + amdgpu_preempt_mgr_sysfs_fini(adev); + amdgpu_device_attr_sysfs_fini(adev); amdgpu_fru_sysfs_fini(adev); @@ -3773,6 +3780,7 @@ int amdgpu_device_init(struct amdgpu_device *adev, spin_lock_init(&adev->irq.lock); + amdgpu_early_init_rlc_reg_funcs(adev); amdgpu_device_init_apu_flags(adev); r = amdgpu_device_check_arguments(adev); @@ -4184,8 +4192,6 @@ static void amdgpu_device_unmap_mmio(struct amdgpu_device *adev) iounmap(adev->rmmio); adev->rmmio = NULL; - if (adev->mman.aper_base_kaddr) - iounmap(adev->mman.aper_base_kaddr); adev->mman.aper_base_kaddr = NULL; /* Memory manager related */ @@ -4210,6 +4216,7 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev) if (adev->mman.initialized) drain_workqueue(adev->mman.bdev.wq); + adev->shutdown = true; unregister_pm_notifier(&adev->pm_nb); @@ -4708,161 +4715,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients) return 0; } -/** - * amdgpu_device_ip_check_soft_reset - did soft reset succeed - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and - * the check_soft_reset callbacks are run. check_soft_reset determines - * if the asic is still hung or not. - * Returns true if any of the IPs are still in a hung state, false if not. - */ -static bool amdgpu_device_ip_check_soft_reset(struct amdgpu_device *adev) -{ - int i; - bool asic_hang = false; - - if (amdgpu_sriov_vf(adev)) - return true; - - if (amdgpu_asic_need_full_reset(adev)) - return true; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].version->funcs->check_soft_reset) - adev->ip_blocks[i].status.hang = - adev->ip_blocks[i].version->funcs->check_soft_reset( - &adev->ip_blocks[i]); - if (adev->ip_blocks[i].status.hang) { - dev_info(adev->dev, "IP block:%s is hung!\n", adev->ip_blocks[i].version->funcs->name); - asic_hang = true; - } - } - return asic_hang; -} - -/** - * amdgpu_device_ip_pre_soft_reset - prepare for soft reset - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and the - * pre_soft_reset callbacks are run if the block is hung. pre_soft_reset - * handles any IP specific hardware or software state changes that are - * necessary for a soft reset to succeed. - * Returns 0 on success, negative error code on failure. - */ -static int amdgpu_device_ip_pre_soft_reset(struct amdgpu_device *adev) -{ - int i, r = 0; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].status.hang && - adev->ip_blocks[i].version->funcs->pre_soft_reset) { - r = adev->ip_blocks[i].version->funcs->pre_soft_reset(&adev->ip_blocks[i]); - if (r) - return r; - } - } - - return 0; -} - -/** - * amdgpu_device_ip_need_full_reset - check if a full asic reset is needed - * - * @adev: amdgpu_device pointer - * - * Some hardware IPs cannot be soft reset. If they are hung, a full gpu - * reset is necessary to recover. - * Returns true if a full asic reset is required, false if not. - */ -static bool amdgpu_device_ip_need_full_reset(struct amdgpu_device *adev) -{ - int i; - - if (amdgpu_asic_need_full_reset(adev)) - return true; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if ((adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) || - (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) || - (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_ACP) || - (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_DCE) || - adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_PSP) { - if (adev->ip_blocks[i].status.hang) { - dev_info(adev->dev, "Some block need full reset!\n"); - return true; - } - } - } - return false; -} - -/** - * amdgpu_device_ip_soft_reset - do a soft reset - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and the - * soft_reset callbacks are run if the block is hung. soft_reset handles any - * IP specific hardware or software state changes that are necessary to soft - * reset the IP. - * Returns 0 on success, negative error code on failure. - */ -static int amdgpu_device_ip_soft_reset(struct amdgpu_device *adev) -{ - int i, r = 0; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].status.hang && - adev->ip_blocks[i].version->funcs->soft_reset) { - r = adev->ip_blocks[i].version->funcs->soft_reset(&adev->ip_blocks[i]); - if (r) - return r; - } - } - - return 0; -} - -/** - * amdgpu_device_ip_post_soft_reset - clean up from soft reset - * - * @adev: amdgpu_device pointer - * - * The list of all the hardware IPs that make up the asic is walked and the - * post_soft_reset callbacks are run if the asic was hung. post_soft_reset - * handles any IP specific hardware or software state changes that are - * necessary after the IP has been soft reset. - * Returns 0 on success, negative error code on failure. - */ -static int amdgpu_device_ip_post_soft_reset(struct amdgpu_device *adev) -{ - int i, r = 0; - - for (i = 0; i < adev->num_ip_blocks; i++) { - if (!adev->ip_blocks[i].status.valid) - continue; - if (adev->ip_blocks[i].status.hang && - adev->ip_blocks[i].version->funcs->post_soft_reset) - r = adev->ip_blocks[i].version->funcs->post_soft_reset(&adev->ip_blocks[i]); - if (r) - return r; - } - - return 0; -} - /** * amdgpu_device_reset_sriov - reset ASIC for SR-IOV vf * @@ -5154,20 +5006,7 @@ int amdgpu_device_pre_asic_reset(struct amdgpu_device *adev, /* Don't suspend on bare metal if we are not going to HW reset the ASIC */ if (!amdgpu_sriov_vf(adev)) { - - if (!need_full_reset) - need_full_reset = amdgpu_device_ip_need_full_reset(adev); - - if (!need_full_reset && amdgpu_gpu_recovery && - amdgpu_device_ip_check_soft_reset(adev)) { - amdgpu_device_ip_pre_soft_reset(adev); - r = amdgpu_device_ip_soft_reset(adev); - amdgpu_device_ip_post_soft_reset(adev); - if (r || amdgpu_device_ip_check_soft_reset(adev)) { - dev_info(adev->dev, "soft reset failed, will fallback to full reset!\n"); - need_full_reset = true; - } - } + need_full_reset = true; if (!test_bit(AMDGPU_SKIP_COREDUMP, &reset_context->flags)) { dev_info(tmp_adev->dev, "Dumping IP State\n"); @@ -5620,8 +5459,7 @@ static void amdgpu_device_halt_activities(struct amdgpu_device *adev, drm_client_dev_suspend(adev_to_drm(tmp_adev)); /* disable ras on ALL IPs */ - if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev) && - amdgpu_device_ip_need_full_reset(tmp_adev)) + if (!need_emergency_restart && !amdgpu_reset_in_dpc(adev)) amdgpu_ras_suspend(tmp_adev); amdgpu_userq_pre_reset(tmp_adev); @@ -6893,7 +6731,7 @@ ssize_t amdgpu_get_soft_full_reset_mask(struct amdgpu_ring *ring) if (unlikely(!ring->adev->debug_disable_soft_recovery) && !amdgpu_sriov_vf(ring->adev) && ring->funcs->soft_recovery) - size |= AMDGPU_RESET_TYPE_SOFT_RESET; + size |= AMDGPU_RESET_TYPE_SOFT_RECOVERY; return size; } @@ -6909,8 +6747,8 @@ ssize_t amdgpu_show_reset_mask(char *buf, uint32_t supported_reset) } - if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RESET) - size += sysfs_emit_at(buf, size, "soft "); + if (supported_reset & AMDGPU_RESET_TYPE_SOFT_RECOVERY) + size += sysfs_emit_at(buf, size, "soft_recovery "); if (supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE) size += sysfs_emit_at(buf, size, "queue "); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c index be5069642a90..a015d55aa158 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.c @@ -22,6 +22,7 @@ */ #include +#include #include "amdgpu.h" #include "amdgpu_discovery.h" @@ -148,6 +149,26 @@ MODULE_FIRMWARE("amdgpu/aldebaran_ip_discovery.bin"); #define mmDRIVER_SCRATCH_1 0x95 #define mmDRIVER_SCRATCH_2 0x96 +struct ip_discovery_top { + struct kobject kobj; + struct kset die_kset; + struct pci_dev *pdev; + struct amdgpu_device *adev; + uint8_t *discovery_bin; + uint32_t bin_size; + bool standalone_mode; +}; + +/* List to track early-initialized ip_discovery_top entries */ +struct early_ip_discovery { + struct list_head list; + struct pci_dev *pdev; + struct ip_discovery_top *ip_top; +}; + +static LIST_HEAD(early_ip_discovery_list); +static DEFINE_MUTEX(early_ip_discovery_mutex); + static const char *hw_id_names[HW_ID_MAX] = { [MP1_HWID] = "MP1", [MP2_HWID] = "MP2", @@ -226,6 +247,7 @@ static const char *hw_id_names[HW_ID_MAX] = { [XGBE_HWID] = "XGBE", [MP0_HWID] = "MP0", [VPE_HWID] = "VPE", + [UMSCH_HWID] = "UMSCH", [ATU_HWID] = "ATU", [AIGC_HWID] = "AIGC", }; @@ -258,6 +280,7 @@ static int hw_id_map[MAX_HWIP] = { [DCI_HWIP] = DCI_HWID, [PCIE_HWIP] = PCIE_HWID, [VPE_HWIP] = VPE_HWID, + [UMSCH_HWIP] = UMSCH_HWID, [ISP_HWIP] = ISP_HWID, [ATU_HWIP] = ATU_HWID, }; @@ -542,25 +565,37 @@ static const char *amdgpu_discovery_get_fw_name(struct amdgpu_device *adev) } } +static struct table_info * +amdgpu_discovery_get_table_info_from_bin(uint8_t *discovery_bin, + uint16_t table_id) +{ + struct binary_header *bhdr = (struct binary_header *)discovery_bin; + struct binary_header_v2 *bhdrv2; + + switch (bhdr->version_major) { + case 2: + bhdrv2 = (struct binary_header_v2 *)discovery_bin; + return &bhdrv2->table_list[table_id]; + case 1: + case 0: + return &bhdr->table_list[table_id]; + default: + return NULL; + } +} + static int amdgpu_discovery_get_table_info(struct amdgpu_device *adev, struct table_info **info, uint16_t table_id) { struct binary_header *bhdr = (struct binary_header *)adev->discovery.bin; - struct binary_header_v2 *bhdrv2; - switch (bhdr->version_major) { - case 2: - bhdrv2 = (struct binary_header_v2 *)adev->discovery.bin; - *info = &bhdrv2->table_list[table_id]; - break; - case 1: - case 0: - *info = &bhdr->table_list[table_id]; - break; - default: - dev_err(adev->dev, "Invalid ip discovery table version %d\n",bhdr->version_major); + *info = amdgpu_discovery_get_table_info_from_bin(adev->discovery.bin, + table_id); + if (!*info) { + dev_err(adev->dev, "Invalid ip discovery table version %d\n", + bhdr->version_major); return -EINVAL; } @@ -724,11 +759,11 @@ static int amdgpu_discovery_init(struct amdgpu_device *adev) return r; } -static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev); - void amdgpu_discovery_fini(struct amdgpu_device *adev) { - amdgpu_discovery_sysfs_fini(adev); + if (adev->discovery.ip_top && !adev->discovery.ip_top->standalone_mode) + amdgpu_discovery_sysfs_fini(adev); + kfree(adev->discovery.bin); adev->discovery.bin = NULL; } @@ -737,15 +772,17 @@ static int amdgpu_discovery_validate_ip(struct amdgpu_device *adev, uint8_t instance, uint16_t hw_id) { if (instance >= HWIP_MAX_INSTANCE) { - dev_err(adev->dev, - "Unexpected instance_number (%d) from ip discovery blob\n", - instance); + if (adev) + dev_err(adev->dev, + "Unexpected instance_number (%d) from ip discovery blob\n", + instance); return -EINVAL; } if (hw_id >= HW_ID_MAX) { - dev_err(adev->dev, - "Unexpected hw_id (%d) from ip discovery blob\n", - hw_id); + if (adev) + dev_err(adev->dev, + "Unexpected hw_id (%d) from ip discovery blob\n", + hw_id); return -EINVAL; } @@ -1111,12 +1148,6 @@ static const struct kobj_type ip_discovery_ktype = { .sysfs_ops = &kobj_sysfs_ops, }; -struct ip_discovery_top { - struct kobject kobj; /* ip_discovery/ */ - struct kset die_kset; /* ip_discovery/die/, contains ip_die_entry */ - struct amdgpu_device *adev; -}; - static void die_kobj_release(struct kobject *kobj) { struct ip_discovery_top *ip_top = container_of(to_kset(kobj), @@ -1132,8 +1163,14 @@ static void ip_disc_release(struct kobject *kobj) kobj); struct amdgpu_device *adev = ip_top->adev; + /* In standalone mode, discovery_bin is managed by devm and will be + * freed automatically when the PCI device is removed. Do not manually + * free it here to avoid double-free. + */ + kfree(ip_top); - adev->discovery.ip_top = NULL; + if (adev) + adev->discovery.ip_top = NULL; } static uint8_t amdgpu_discovery_get_harvest_info(struct amdgpu_device *adev, @@ -1141,6 +1178,10 @@ static uint8_t amdgpu_discovery_get_harvest_info(struct amdgpu_device *adev, { uint8_t harvest = 0; + /* In early init mode (adev == NULL), harvest info is not available */ + if (!adev) + return 0; + /* Until a uniform way is figured, get mask based on hwid */ switch (hw_id) { case VCN_HWID: @@ -1169,11 +1210,14 @@ static uint8_t amdgpu_discovery_get_harvest_info(struct amdgpu_device *adev, } static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev, + struct ip_discovery_top *ip_top, struct ip_die_entry *ip_die_entry, const size_t _ip_offset, const int num_ips, bool reg_base_64) { - uint8_t *discovery_bin = adev->discovery.bin; + uint8_t *discovery_bin = ip_top->standalone_mode ? + ip_top->discovery_bin : + adev->discovery.bin; int ii, jj, kk, res; uint16_t hw_id; uint8_t inst; @@ -1270,10 +1314,12 @@ static int amdgpu_discovery_sysfs_ips(struct amdgpu_device *adev, return 0; } -static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev) +static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev, + struct ip_discovery_top *ip_top) { - struct ip_discovery_top *ip_top = adev->discovery.ip_top; - uint8_t *discovery_bin = adev->discovery.bin; + uint8_t *discovery_bin = ip_top->standalone_mode ? + ip_top->discovery_bin : + adev->discovery.bin; struct table_info *info; struct ip_discovery_header *ihdr; struct die_header *dhdr; @@ -1282,9 +1328,10 @@ static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev) size_t ip_offset; int ii, res; - res = amdgpu_discovery_get_table_info(adev, &info, IP_DISCOVERY); - if (res) - return res; + info = amdgpu_discovery_get_table_info_from_bin(discovery_bin, + IP_DISCOVERY); + if (!info) + return -EINVAL; ihdr = (struct ip_discovery_header *)(discovery_bin + le16_to_cpu(info->offset)); @@ -1322,7 +1369,8 @@ static int amdgpu_discovery_sysfs_recurse(struct amdgpu_device *adev) return res; } - amdgpu_discovery_sysfs_ips(adev, ip_die_entry, ip_offset, num_ips, !!ihdr->base_addr_64_bit); + amdgpu_discovery_sysfs_ips(adev, ip_top, ip_die_entry, ip_offset, + num_ips, !!ihdr->base_addr_64_bit); } return 0; @@ -1338,12 +1386,30 @@ static int amdgpu_discovery_sysfs_init(struct amdgpu_device *adev) if (!discovery_bin) return -EINVAL; + /* If early init already created sysfs in standalone mode, skip normal init */ + if (adev->discovery.ip_top && adev->discovery.ip_top->standalone_mode) + return 0; + ip_top = kzalloc_obj(*ip_top); if (!ip_top) return -ENOMEM; ip_top->adev = adev; - adev->discovery.ip_top = ip_top; + + /* Check if ip_discovery already exists before creating. + * This shouldn't normally happen but handle it gracefully. + */ + if (adev->dev->kobj.sd) { + struct kernfs_node *existing; + + existing = kernfs_find_and_get(adev->dev->kobj.sd, "ip_discovery"); + if (existing) { + kernfs_put(existing); + kfree(ip_top); + return 0; + } + } + res = kobject_init_and_add(&ip_top->kobj, &ip_discovery_ktype, &adev->dev->kobj, "ip_discovery"); if (res) { @@ -1351,6 +1417,8 @@ static int amdgpu_discovery_sysfs_init(struct amdgpu_device *adev) goto Err; } + adev->discovery.ip_top = ip_top; + die_kset = &ip_top->die_kset; kobject_set_name(&die_kset->kobj, "%s", "die"); die_kset->kobj.parent = &ip_top->kobj; @@ -1365,7 +1433,7 @@ static int amdgpu_discovery_sysfs_init(struct amdgpu_device *adev) ip_hw_instance_attrs[ii] = &ip_hw_attr[ii].attr; ip_hw_instance_attrs[ii] = NULL; - res = amdgpu_discovery_sysfs_recurse(adev); + res = amdgpu_discovery_sysfs_recurse(adev, ip_top); return res; Err: @@ -1412,7 +1480,7 @@ static void amdgpu_discovery_sysfs_die_free(struct ip_die_entry *ip_die_entry) kobject_put(&ip_die_entry->ip_kset.kobj); } -static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev) +void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev) { struct ip_discovery_top *ip_top = adev->discovery.ip_top; struct list_head *el, *tmp; @@ -1421,6 +1489,16 @@ static void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev) if (!ip_top) return; + /* + * In standalone mode the sysfs hierarchy is tied to the PCI device + * lifetime and is torn down by amdgpu_discovery_sysfs_early_fini(). + * Freeing it here would leave a dangling pointer in the early + * discovery list, causing a use-after-free on driver unbind. + */ + if (ip_top->standalone_mode) + return; + + adev->discovery.ip_top = NULL; die_kset = &ip_top->die_kset; spin_lock(&die_kset->list_lock); list_for_each_prev_safe(el, tmp, &die_kset->list) { @@ -1479,6 +1557,150 @@ void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p) spin_unlock(&die_kset->list_lock); } +int amdgpu_discovery_sysfs_early_init(struct amdgpu_device *adev, struct pci_dev *pdev) +{ + struct ip_discovery_top *ip_top; + struct early_ip_discovery *early_entry, *tmp; + struct kset *die_kset; + uint8_t *discovery_bin; + int res, ii; + + if (!adev || !adev->discovery.bin) + return -EINVAL; + + if (adev->discovery.ip_top) + return 0; + + mutex_lock(&early_ip_discovery_mutex); + list_for_each_entry_safe(early_entry, tmp, &early_ip_discovery_list, list) { + if (early_entry->pdev == pdev) { + adev->discovery.ip_top = early_entry->ip_top; + early_entry->ip_top->adev = adev; + mutex_unlock(&early_ip_discovery_mutex); + return 0; + } + } + mutex_unlock(&early_ip_discovery_mutex); + + discovery_bin = adev->discovery.bin; + + early_entry = kzalloc(sizeof(*early_entry), GFP_KERNEL); + if (!early_entry) + return -ENOMEM; + + ip_top = kzalloc(sizeof(*ip_top), GFP_KERNEL); + if (!ip_top) { + kfree(early_entry); + return -ENOMEM; + } + + ip_top->discovery_bin = devm_kmemdup(&pdev->dev, discovery_bin, + DISCOVERY_TMR_SIZE, GFP_KERNEL); + if (!ip_top->discovery_bin) { + kfree(ip_top); + kfree(early_entry); + return -ENOMEM; + } + + ip_top->bin_size = DISCOVERY_TMR_SIZE; + ip_top->pdev = pdev; + ip_top->adev = adev; + ip_top->standalone_mode = true; + + /* Check if ip_discovery already exists (from previous probe attempt). + * This can happen if the module was unloaded and reloaded but the + * sysfs persisted (tied to PCI device lifetime). + */ + if (pdev->dev.kobj.sd) { + struct kernfs_node *existing; + + existing = kernfs_find_and_get(pdev->dev.kobj.sd, "ip_discovery"); + if (existing) { + kernfs_put(existing); + kfree(ip_top); + kfree(early_entry); + return 0; + } + } + + res = kobject_init_and_add(&ip_top->kobj, &ip_discovery_ktype, + &pdev->dev.kobj, "ip_discovery"); + if (res) + goto err_put_kobj; + + adev->discovery.ip_top = ip_top; + + die_kset = &ip_top->die_kset; + kobject_set_name(&die_kset->kobj, "%s", "die"); + die_kset->kobj.parent = &ip_top->kobj; + die_kset->kobj.ktype = &die_kobj_ktype; + res = kset_register(&ip_top->die_kset); + if (res) + goto err_put_die_kset; + + for (ii = 0; ii < ARRAY_SIZE(ip_hw_attr); ii++) + ip_hw_instance_attrs[ii] = &ip_hw_attr[ii].attr; + ip_hw_instance_attrs[ii] = NULL; + + res = amdgpu_discovery_sysfs_recurse(NULL, ip_top); + if (res) + goto err_put_die_kset; + + early_entry->pdev = pdev; + early_entry->ip_top = ip_top; + mutex_lock(&early_ip_discovery_mutex); + list_add(&early_entry->list, &early_ip_discovery_list); + mutex_unlock(&early_ip_discovery_mutex); + + return 0; + +err_put_die_kset: + kobject_put(&ip_top->die_kset.kobj); +err_put_kobj: + kobject_put(&ip_top->kobj); + kfree(early_entry); + adev->discovery.ip_top = NULL; + return res; +} + +void amdgpu_discovery_sysfs_early_fini(struct pci_dev *pdev) +{ + struct early_ip_discovery *entry, *tmp_entry; + struct ip_discovery_top *ip_top = NULL; + struct list_head *el, *tmp; + struct kset *die_kset; + + /* Find the entry in our tracking list */ + mutex_lock(&early_ip_discovery_mutex); + list_for_each_entry_safe(entry, tmp_entry, &early_ip_discovery_list, list) { + if (entry->pdev == pdev) { + ip_top = entry->ip_top; + list_del(&entry->list); + kfree(entry); + break; + } + } + mutex_unlock(&early_ip_discovery_mutex); + + if (!ip_top) + return; + + /* Clean up sysfs hierarchy */ + die_kset = &ip_top->die_kset; + + spin_lock(&die_kset->list_lock); + list_for_each_prev_safe(el, tmp, &die_kset->list) { + list_del_init(el); + spin_unlock(&die_kset->list_lock); + amdgpu_discovery_sysfs_die_free(to_ip_die_entry(list_to_kobj(el))); + spin_lock(&die_kset->list_lock); + } + spin_unlock(&die_kset->list_lock); + + kobject_put(&ip_top->die_kset.kobj); + kobject_put(&ip_top->kobj); + /* ip_top itself will be freed by kobject_put via ip_disc_release */ +} /* ================================================== */ @@ -1504,6 +1726,9 @@ static int amdgpu_discovery_reg_base_init(struct amdgpu_device *adev) r = amdgpu_discovery_init(adev); if (r) return r; + + amdgpu_discovery_sysfs_early_init(adev, adev->pdev); + discovery_bin = adev->discovery.bin; wafl_ver = 0; adev->gfx.xcc_mask = 0; @@ -2119,6 +2344,8 @@ static int amdgpu_discovery_set_common_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): amdgpu_device_ip_block_add(adev, &soc21_common_ip_block); break; case IP_VERSION(12, 0, 0): @@ -2180,6 +2407,8 @@ static int amdgpu_discovery_set_gmc_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): amdgpu_device_ip_block_add(adev, &gmc_v11_0_ip_block); break; case IP_VERSION(12, 0, 0): @@ -2506,6 +2735,8 @@ static int amdgpu_discovery_set_gc_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): amdgpu_device_ip_block_add(adev, &gfx_v11_0_ip_block); break; case IP_VERSION(12, 0, 0): @@ -2630,7 +2861,12 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev) return -EINVAL; } } else { - switch (amdgpu_ip_version(adev, UVD_HWIP, 0)) { + uint32_t vcn_version = amdgpu_ip_version(adev, UVD_HWIP, 0); + + /* no VCN discovered; nothing to add */ + if (!vcn_version) + return 0; + switch (vcn_version) { case IP_VERSION(1, 0, 0): case IP_VERSION(1, 0, 1): amdgpu_device_ip_block_add(adev, &vcn_v1_0_ip_block); @@ -2698,7 +2934,7 @@ static int amdgpu_discovery_set_mm_ip_blocks(struct amdgpu_device *adev) default: dev_err(adev->dev, "Failed to add vcn/jpeg ip block(UVD_HWIP:0x%x)\n", - amdgpu_ip_version(adev, UVD_HWIP, 0)); + vcn_version); return -EINVAL; } } @@ -2719,6 +2955,8 @@ static int amdgpu_discovery_set_mes_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): amdgpu_device_ip_block_add(adev, &mes_v11_0_ip_block); adev->enable_mes = true; adev->enable_mes_kiq = true; @@ -3127,6 +3365,8 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): adev->family = AMDGPU_FAMILY_GC_11_5_0; break; case IP_VERSION(12, 0, 0): @@ -3156,6 +3396,8 @@ int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): adev->flags |= AMD_IS_APU; break; default: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h index e0010f6a3eda..5b2b16f68576 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_discovery.h @@ -41,6 +41,7 @@ struct amdgpu_discovery_info { bool reserve_tmr; }; +void amdgpu_discovery_sysfs_fini(struct amdgpu_device *adev); void amdgpu_discovery_fini(struct amdgpu_device *adev); int amdgpu_discovery_set_ip_blocks(struct amdgpu_device *adev); @@ -53,4 +54,9 @@ int amdgpu_discovery_get_gc_major_minor_version(struct amdgpu_device *adev, void amdgpu_discovery_dump(struct amdgpu_device *adev, struct drm_printer *p); +/* Early sysfs functions for persistent ip_discovery export */ +int amdgpu_discovery_sysfs_early_init(struct amdgpu_device *adev, + struct pci_dev *pdev); +void amdgpu_discovery_sysfs_early_fini(struct pci_dev *pdev); + #endif /* __AMDGPU_DISCOVERY__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index bf4260269681..ad631ad31899 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -146,7 +145,9 @@ enum AMDGPU_DEBUG_MASK { AMDGPU_DEBUG_SMU_POOL = BIT(7), AMDGPU_DEBUG_VM_USERPTR = BIT(8), AMDGPU_DEBUG_DISABLE_RAS_CE_LOG = BIT(9), - AMDGPU_DEBUG_ENABLE_CE_CS = BIT(10) + AMDGPU_DEBUG_ENABLE_CE_CS = BIT(10), + AMDGPU_DEBUG_HIBERNATION_THAW_RESUME_GPU = BIT(11), + AMDGPU_DEBUG_DISABLE_IP_BLOCK_SOFT_RESET = BIT(12), }; unsigned int amdgpu_vram_limit = UINT_MAX; @@ -1939,6 +1940,7 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x6646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY}, {0x1002, 0x6647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE|AMD_IS_MOBILITY}, {0x1002, 0x6649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE}, + {0x1002, 0x664D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE}, {0x1002, 0x6650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE}, {0x1002, 0x6651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE}, {0x1002, 0x6658, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_BONAIRE}, @@ -2008,6 +2010,7 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x6930, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, {0x1002, 0x6938, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, {0x1002, 0x6939, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, + {0x1002, 0x693B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TONGA}, /* fiji */ {0x1002, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_FIJI}, {0x1002, 0x730F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_FIJI}, @@ -2036,6 +2039,7 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x67C4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67C7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67D0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, + {0x1002, 0x67D4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67C8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67C9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, @@ -2049,6 +2053,7 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, {0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, {0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + {0x1002, 0x698F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, {0x1002, 0x6995, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, {0x1002, 0x6997, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, @@ -2250,7 +2255,7 @@ static void amdgpu_init_debug_options(struct amdgpu_device *adev) } if (amdgpu_debug_mask & AMDGPU_DEBUG_DISABLE_GPU_SOFT_RECOVERY) { - pr_info("debug: soft reset for GPU recovery disabled\n"); + pr_info("debug: soft recovery disabled\n"); adev->debug_disable_soft_recovery = true; } @@ -2291,6 +2296,16 @@ static void amdgpu_init_debug_options(struct amdgpu_device *adev) pr_info("debug: allowing command submission to CE engine\n"); adev->debug_enable_ce_cs = true; } + + if (amdgpu_debug_mask & AMDGPU_DEBUG_HIBERNATION_THAW_RESUME_GPU) { + pr_info("debug: resume gpu in thaw() of hibernation\n"); + adev->debug_hibernation_thaw_resume_gpu = true; + } + + if (amdgpu_debug_mask & AMDGPU_DEBUG_DISABLE_IP_BLOCK_SOFT_RESET) { + pr_info("debug: IP block soft reset disabled\n"); + adev->debug_disable_ip_block_soft_reset = true; + } } static unsigned long amdgpu_fix_asic_type(struct pci_dev *pdev, unsigned long flags) @@ -2552,6 +2567,8 @@ amdgpu_pci_remove(struct pci_dev *pdev) amdgpu_driver_unload_kms(dev); + amdgpu_discovery_sysfs_early_fini(pdev); + /* * Flush any in flight DMA operations from device. * Clear the Bus Master Enable bit and then wait on the PCIe Device @@ -2705,9 +2722,10 @@ static int amdgpu_pmops_freeze(struct device *dev) static int amdgpu_pmops_thaw(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); + struct amdgpu_device *adev = drm_to_adev(drm_dev); /* do not resume device if it's normal hibernation */ - if (console_suspend_enabled && + if (!adev->debug_hibernation_thaw_resume_gpu && !pm_hibernate_is_recovering() && !pm_hibernation_mode_is_suspend()) return 0; @@ -3076,6 +3094,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = { DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_SIGNAL, amdgpu_userq_signal_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_USERQ_WAIT, amdgpu_userq_wait_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), DRM_IOCTL_DEF_DRV(AMDGPU_GEM_LIST_HANDLES, amdgpu_gem_list_handles_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(AMDGPU_PROC_OPTIONS, amdgpu_proc_options_ioctl, DRM_AUTH|DRM_RENDER_ALLOW), }; static const struct drm_driver amdgpu_kms_driver = { @@ -3196,6 +3215,14 @@ static void __exit amdgpu_exit(void) amdgpu_sync_fini(); mmu_notifier_synchronize(); amdgpu_xcp_drv_release(); + + /* + * Flush outstanding call_rcu() callbacks before the + * module text is freed. Otherwise a grace period elapsing after + * unload invokes a callback in already-freed module memory and + * faults in rcu_do_batch(). + */ + rcu_barrier(); } module_init(amdgpu_init); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index ea69b1bac7c6..3043ad041bb4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -727,6 +727,15 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct amdgpu_ring *ring, last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask; seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask; + /* If there is nothing to reemit, return early and set an error on the fence + * if applicable. If all of the fences are siganlled, this will be a nop. + * if there are still fences and ring_backup_entries_to_copy is 0, then + * we are skipping it on purpose. + */ + if (!ring->ring_backup_entries_to_copy) { + amdgpu_fence_driver_force_completion(ring, &guilty_fence->base); + return; + } ring->reemit = true; amdgpu_ring_alloc(ring, ring->ring_backup_entries_to_copy); spin_lock_irqsave(&ring->fence_drv.lock, flags); @@ -741,7 +750,8 @@ void amdgpu_ring_set_fence_errors_and_reemit(struct amdgpu_ring *ring, if (unprocessed && !dma_fence_is_signaled_locked(unprocessed)) { fence = container_of(unprocessed, struct amdgpu_fence, base); is_guilty_fence = fence == guilty_fence; - is_guilty_context = fence->context == guilty_fence->context; + is_guilty_context = guilty_fence ? + (fence->context == guilty_fence->context) : false; /* mark all fences from the guilty context with an error */ if (is_guilty_fence) @@ -794,6 +804,17 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring, seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask; ring->ring_backup_entries_to_copy = 0; + /* if we've already seen this fence, return early. + * ring->ring_backup_entries_to_copy is set to 0 so + * the reemit helper will return early as well to + * avoid getting stuck in a reemit loop. + */ + if (ring->guilty_fence == guilty_fence) { + ring->guilty_fence = NULL; + return; + } + ring->guilty_fence = guilty_fence; + do { last_seq++; last_seq &= ring->fence_drv.num_fences_mask; @@ -811,6 +832,36 @@ void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring, } while (last_seq != seq); } +struct amdgpu_fence * +amdgpu_ring_find_guilty_fence(struct amdgpu_ring *ring) +{ + struct dma_fence *unprocessed; + struct dma_fence __rcu **ptr; + struct amdgpu_fence *fence; + u32 seq, last_seq; + + last_seq = amdgpu_fence_read(ring) & ring->fence_drv.num_fences_mask; + seq = ring->fence_drv.sync_seq & ring->fence_drv.num_fences_mask; + + do { + last_seq++; + last_seq &= ring->fence_drv.num_fences_mask; + + ptr = &ring->fence_drv.fences[last_seq]; + rcu_read_lock(); + unprocessed = rcu_dereference(*ptr); + + if (unprocessed && !dma_fence_is_signaled(unprocessed)) { + fence = container_of(unprocessed, struct amdgpu_fence, base); + rcu_read_unlock(); + return fence; + } + rcu_read_unlock(); + } while (last_seq != seq); + + return NULL; +} + /* * Common fence implementation */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 76da3f932f24..6a0699746fbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -535,6 +535,7 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, bo = gem_to_amdgpu_bo(gobj); bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; + bo->parent = amdgpu_bo_ref(fpriv->vm.root.bo); r = amdgpu_ttm_tt_set_userptr(&bo->tbo, args->addr, args->flags); if (r) goto release_object; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index 85372af1216d..96c9d4f00b27 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -34,6 +34,7 @@ #include "amdgpu_xcp.h" #include "amdgpu_xgmi.h" #include "amdgpu_mes.h" +#include "mes_userqueue.h" #include "nvd.h" /* delay 0.1 second to enable gfx off feature */ @@ -377,6 +378,30 @@ int amdgpu_gfx_kiq_init(struct amdgpu_device *adev, return 0; } +static void amdgpu_gfx_mqd_reset_restore(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + int mqd_idx, mqd_size; + + /* restore mqd with the backup copy */ + if (ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) { + mqd_idx = ring - &adev->gfx.compute_ring[0]; + mqd_size = adev->mqds[AMDGPU_HW_IP_COMPUTE].mqd_size; + if (adev->gfx.mec.mqd_backup[mqd_idx]) + memcpy_toio(ring->mqd_ptr, adev->gfx.mec.mqd_backup[mqd_idx], mqd_size); + } else if (ring->funcs->type == AMDGPU_RING_TYPE_GFX) { + mqd_size = adev->mqds[AMDGPU_HW_IP_GFX].mqd_size; + mqd_idx = ring - &adev->gfx.gfx_ring[0]; + + if (adev->gfx.me.mqd_backup[mqd_idx]) + memcpy_toio(ring->mqd_ptr, adev->gfx.me.mqd_backup[mqd_idx], mqd_size); + } + /* reset the ring */ + ring->wptr = 0; + atomic64_set((atomic64_t *)ring->wptr_cpu_addr, 0); + amdgpu_ring_clear_ring(ring); +} + /* create MQD for each compute/gfx queue */ int amdgpu_gfx_mqd_sw_init(struct amdgpu_device *adev, unsigned int mqd_size, int xcc_id) @@ -1964,6 +1989,60 @@ static ssize_t amdgpu_gfx_get_compute_reset_mask(struct device *dev, return amdgpu_show_reset_mask(buf, adev->gfx.compute_supported_reset); } +static int amdgpu_gfx_mes_reset_queue_start(struct amdgpu_ring *ring, + unsigned int vmid, + struct amdgpu_fence *timedout_fence, + bool use_mmio) +{ + struct amdgpu_device *adev = ring->adev; + bool reinit_queue; + int r; + + if ((ring->funcs->type == AMDGPU_RING_TYPE_COMPUTE) && + adev->mes.compute_pipe_reset_enabled) + reinit_queue = true; + else if ((ring->funcs->type == AMDGPU_RING_TYPE_GFX) && + adev->mes.gfx_pipe_reset_enabled) + reinit_queue = true; + else + reinit_queue = use_mmio; + + amdgpu_ring_reset_helper_begin(ring, timedout_fence); + + r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0); + if (r) + return r; + + if (reinit_queue) { + r = amdgpu_mes_unmap_legacy_queue(adev, ring, + RESET_QUEUES, 0, 0, 0); + if (r) + return r; + amdgpu_gfx_mqd_reset_restore(ring); + + r = amdgpu_mes_map_legacy_queue(adev, ring, 0); + if (r) { + dev_err(adev->dev, "failed to remap kgq\n"); + return r; + } + } + return 0; +} + +int amdgpu_gfx_mes_reset_queue(struct amdgpu_ring *ring, + unsigned int vmid, + struct amdgpu_fence *timedout_fence, + bool use_mmio) +{ + int r; + + r = amdgpu_gfx_mes_reset_queue_start(ring, vmid, timedout_fence, + use_mmio); + if (r) + return r; + return amdgpu_ring_reset_helper_end(ring, timedout_fence); +} + static DEVICE_ATTR(run_cleaner_shader, 0200, NULL, amdgpu_gfx_set_run_cleaner_shader); @@ -2122,6 +2201,200 @@ void amdgpu_gfx_sysfs_fini(struct amdgpu_device *adev) } } +static void amdgpu_gfx_reset_start_compute_scheds(struct amdgpu_device *adev, + struct amdgpu_ring *guilty_ring) +{ + struct amdgpu_ring *ring; + int i; + + for (i = 0; i < adev->gfx.num_compute_rings; i++) { + ring = &adev->gfx.compute_ring[i]; + if (ring == guilty_ring) + continue; + drm_sched_wqueue_start(&ring->sched); + } +} + +static void amdgpu_gfx_reset_stop_compute_scheds(struct amdgpu_device *adev, + struct amdgpu_ring *guilty_ring) +{ + struct amdgpu_ring *ring; + int i; + + for (i = 0; i < adev->gfx.num_compute_rings; i++) { + ring = &adev->gfx.compute_ring[i]; + if (ring == guilty_ring) + continue; + drm_sched_wqueue_stop(&ring->sched); + } +} + +/* + * Match the MES-reported hung doorbell against a compute ring and run + * the reset. On hit, the matched ring and its guilty fence are returned + * via *out_ring / *out_fence so the caller can defer reset end until + * after MES has resumed all gangs. + */ +static int amdgpu_gfx_reset_mes_kcq(struct amdgpu_device *adev, + struct amdgpu_ring *guilty_ring, + unsigned int db, + struct amdgpu_ring **out_ring, + struct amdgpu_fence **out_fence) +{ + bool use_mmio = adev->gfx.mec.use_mmio_for_reset; + struct amdgpu_fence *fence; + struct amdgpu_ring *ring; + int i, r; + + *out_ring = NULL; + *out_fence = NULL; + for (i = 0; i < adev->gfx.num_compute_rings; i++) { + ring = &adev->gfx.compute_ring[i]; + if (ring == guilty_ring) + continue; + if (ring->doorbell_index == db) { + fence = amdgpu_ring_find_guilty_fence(ring); + r = amdgpu_gfx_mes_reset_queue_start(ring, 0, fence, + use_mmio); + if (r) + return r; + *out_ring = ring; + *out_fence = fence; + break; + } + } + return 0; +} + +int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + struct amdgpu_fence *guilty_fence, + struct amdgpu_usermode_queue *uq, + unsigned int *hung_queue_count, + void *faulty_queue_input) +{ + struct amdgpu_mes_hung_queue_hqd_info *hqd_info = + (struct amdgpu_mes_hung_queue_hqd_info *) + &adev->gfx.mec.mes_hung_db_array[adev->mes.hung_queue_hqd_info_offset]; + int i, r, pipe, queue, queue_type; + unsigned int num_hung = 0; + bool use_mmio = adev->gfx.mec.use_mmio_for_reset; + struct mes_remove_queue_input *queue_input = (struct mes_remove_queue_input *)faulty_queue_input; + struct amdgpu_gfx_deferred_entry deferred_end[AMDGPU_MAX_COMPUTE_RINGS + 1]; + int n_deferred = 0; + int ring_err; + + guard(mutex)(&adev->gfx.mec.reset_mutex); + /* stop the drm schedulers for all compute queues */ + amdgpu_gfx_reset_stop_compute_scheds(adev, ring); + /* suspend all will determine which queues are hung. + * reset detect will return the array of bad queue doorbells + */ + r = amdgpu_mes_suspend(adev, 0); + /* if suspend all success, it should no hang queue */ + if (!r) + /* always reset the KCQ/userq since we need to signal the fence + * and we could be stuck in a loop which is preemptable. + */ + goto fence_reset; + r = amdgpu_mes_detect_and_reset_hung_queues(adev, AMDGPU_RING_TYPE_COMPUTE, + true, &num_hung, adev->gfx.mec.mes_hung_db_array, 0); + if (r) + goto out; + if (hung_queue_count) + *hung_queue_count = num_hung; + +fence_reset: + /* reset the queue this came from if specified */ + if (ring) { + r = amdgpu_gfx_mes_reset_queue_start(ring, 0, guilty_fence, + use_mmio); + if (r) + goto out; + deferred_end[n_deferred].ring = ring; + deferred_end[n_deferred].fence = guilty_fence; + n_deferred++; + } + if (uq) { + r = mes_userq_reset(uq); + if (r) + goto out; + } + for (i = 0; i < num_hung; i++) { + struct amdgpu_ring *hr = NULL; + struct amdgpu_fence *hf = NULL; + + pipe = hqd_info[i].pipe_index; + queue = hqd_info[i].queue_index; + queue_type = hqd_info[i].queue_type; + + /* reset any KCQs */ + r = amdgpu_gfx_reset_mes_kcq(adev, ring, + adev->gfx.mec.mes_hung_db_array[i], + &hr, &hf); + if (r) + goto out; + if (hr) { + deferred_end[n_deferred].ring = hr; + deferred_end[n_deferred].fence = hf; + n_deferred++; + } + /* reset any KFD queues */ + r = amdgpu_amdkfd_reset_mes_queue(adev, 0, queue_type, pipe, queue, + adev->gfx.mec.mes_hung_db_array[i]); + if (r) + goto out; + /* reset KGD user queues */ + r = mes_userq_reset_queue(adev, uq, queue_type, pipe, queue, + adev->gfx.mec.mes_hung_db_array[i]); + if (r) + goto out; + } + + /* MES doesn't detect any hung queue but we have a known bad queue + * and it is not KCQ + */ + if (!num_hung && queue_input && !ring) { + /* MES suspend_all is successful means this bad queue is + * preempted successfuly. Remove it before resume all so it + * doesn't get mapped back + */ + if (!down_read_trylock(&adev->reset_domain->sem)) { + r = -EIO; + goto out; + } + amdgpu_mes_lock(&adev->mes); + r = adev->mes.funcs->remove_hw_queue(&adev->mes, queue_input); + amdgpu_mes_unlock(&adev->mes); + up_read(&adev->reset_domain->sem); + } + +out: + /* resume all will enable the non-hung queues */ + amdgpu_mes_resume(adev, 0); + + /* Now CP is running again — replay backed-up commands and ring + * doorbells on each reset queue. + */ + ring_err = r; + for (i = 0; i < n_deferred; i++) { + int er = amdgpu_ring_reset_helper_end(deferred_end[i].ring, + deferred_end[i].fence); + + if (er && !ring_err) + ring_err = er; + } + + if (!ring_err) + amdgpu_gfx_reset_start_compute_scheds(adev, ring); + + /* If this reset is triggered by non-KCQ, the KCQ result after resume must + * not override the reset result; otherwise a false reset failure is returned + * to the non-KCQ caller + */ + return ring ? ring_err : r; +} + int amdgpu_gfx_cleaner_shader_sw_init(struct amdgpu_device *adev, unsigned int cleaner_shader_size) { @@ -2460,9 +2733,8 @@ void amdgpu_gfx_profile_ring_begin_use(struct amdgpu_ring *ring) else profile = PP_SMC_POWER_PROFILE_COMPUTE; - atomic_inc(&adev->gfx.total_submission_cnt); - - cancel_delayed_work_sync(&adev->gfx.idle_work); + if (!atomic_fetch_inc(&adev->gfx.total_submission_cnt)) + cancel_delayed_work_sync(&adev->gfx.idle_work); /* We can safely return early here because we've cancelled the * the delayed work so there is no one else to set it to false @@ -2490,9 +2762,9 @@ void amdgpu_gfx_profile_ring_end_use(struct amdgpu_ring *ring) if (amdgpu_dpm_is_overdrive_enabled(adev)) return; - atomic_dec(&ring->adev->gfx.total_submission_cnt); - - schedule_delayed_work(&ring->adev->gfx.idle_work, GFX_PROFILE_IDLE_TIMEOUT); + if (atomic_dec_and_test(&ring->adev->gfx.total_submission_cnt)) + schedule_delayed_work(&ring->adev->gfx.idle_work, + GFX_PROFILE_IDLE_TIMEOUT); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 54c1eb9c499b..aefd4f03b443 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -36,6 +36,8 @@ #include "amdgpu_ring_mux.h" #include "amdgpu_xcp.h" +struct amdgpu_usermode_queue; + /* GFX current status */ #define AMDGPU_GFX_NORMAL_MODE 0x00000000L #define AMDGPU_GFX_SAFE_MODE 0x00000001L @@ -116,6 +118,9 @@ struct amdgpu_mec { u32 num_pipe_per_mec; u32 num_queue_per_pipe; void *mqd_backup[AMDGPU_MAX_COMPUTE_RINGS * AMDGPU_MAX_GC_INSTANCES]; + bool use_mmio_for_reset; + u32 *mes_hung_db_array; + struct mutex reset_mutex; }; struct amdgpu_mec_bitmap { @@ -401,6 +406,7 @@ struct amdgpu_me { uint32_t num_pipe_per_me; uint32_t num_queue_per_pipe; void *mqd_backup[AMDGPU_MAX_GFX_RINGS]; + bool use_mmio_for_reset; /* These are the resources for which amdgpu takes ownership */ DECLARE_BITMAP(queue_bitmap, AMDGPU_MAX_GFX_QUEUES); @@ -479,8 +485,6 @@ struct amdgpu_gfx { const struct amdgpu_gfx_funcs *funcs; /* reset mask */ - uint32_t grbm_soft_reset; - uint32_t srbm_soft_reset; uint32_t gfx_supported_reset; uint32_t compute_supported_reset; @@ -543,6 +547,11 @@ struct amdgpu_gfx { bool disable_uq; }; +struct amdgpu_gfx_deferred_entry { + struct amdgpu_ring *ring; + struct amdgpu_fence *fence; +}; + struct amdgpu_gfx_ras_reg_entry { struct amdgpu_ras_err_status_reg_entry reg_entry; enum amdgpu_gfx_ras_mem_id_type mem_id_type; @@ -641,6 +650,12 @@ int amdgpu_gfx_poison_consumption_handler(struct amdgpu_device *adev, bool amdgpu_gfx_is_master_xcc(struct amdgpu_device *adev, int xcc_id); int amdgpu_gfx_sysfs_init(struct amdgpu_device *adev); void amdgpu_gfx_sysfs_fini(struct amdgpu_device *adev); +int amdgpu_gfx_reset_mes_compute(struct amdgpu_device *adev, + struct amdgpu_ring *ring, + struct amdgpu_fence *guilty_fence, + struct amdgpu_usermode_queue *uq, + unsigned int *hung_queue_count, + void *faulty_queue_input); void amdgpu_gfx_ras_error_func(struct amdgpu_device *adev, void *ras_error_status, void (*func)(struct amdgpu_device *adev, void *ras_error_status, @@ -667,6 +682,11 @@ void amdgpu_debugfs_compute_sched_mask_init(struct amdgpu_device *adev); int amdgpu_gfx_ring_preempt_ib(struct amdgpu_ring *ring); +int amdgpu_gfx_mes_reset_queue(struct amdgpu_ring *ring, + unsigned int vmid, + struct amdgpu_fence *timedout_fence, + bool use_mmio); + static inline const char *amdgpu_gfx_compute_mode_desc(int mode) { switch (mode) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c index 5f7745143f56..4000b2c6fc98 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c @@ -977,6 +977,8 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): /* Don't enable it by default yet. */ if (amdgpu_tmz < 1) { @@ -1761,10 +1763,15 @@ int amdgpu_gmc_init_mem_ranges(struct amdgpu_device *adev) valid = true; else valid = amdgpu_gmc_validate_partition_info(adev); - if (!valid) { - /* TODO: handle invalid case */ + if (!valid) dev_warn(adev->dev, "Mem ranges not matching with hardware config\n"); + + if (!adev->gmc.num_mem_partitions) { + dev_err(adev->dev, "num_mem_partitions is zero\n"); + kfree(adev->gmc.mem_partitions); + adev->gmc.mem_partitions = NULL; + return -EINVAL; } return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h index ddb0d500e0fa..3ca187f5ade8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.h @@ -286,7 +286,6 @@ struct amdgpu_gmc { struct amdgpu_irq_src vm_fault; uint32_t vram_type; uint8_t vram_vendor; - uint32_t srbm_soft_reset; bool prt_warning; uint32_t sdpif_register; /* apertures */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c index 99bc9ad67d5b..a7d13e337d84 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_hmm.c @@ -67,7 +67,6 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni, { struct amdgpu_bo *bo = container_of(mni, struct amdgpu_bo, notifier); struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); - struct amdgpu_bo *vm_root = bo->vm_bo->vm->root.bo; long r; if (!mmu_notifier_range_blockable(range)) @@ -78,7 +77,7 @@ static bool amdgpu_hmm_invalidate_gfx(struct mmu_interval_notifier *mni, mmu_interval_set_seq(mni, cur_seq); amdgpu_vm_bo_invalidate(bo, false); - r = dma_resv_wait_timeout(vm_root->tbo.base.resv, + r = dma_resv_wait_timeout(bo->parent->tbo.base.resv, DMA_RESV_USAGE_BOOKKEEP, false, MAX_SCHEDULE_TIMEOUT); mutex_unlock(&adev->notifier_lock); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c index 6aa54156bbc9..33a04113ed74 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.c @@ -368,27 +368,6 @@ int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev, return 0; } -/** - * amdgpu_device_ip_is_hw - is the hardware IP enabled - * - * @adev: amdgpu_device pointer - * @block_type: Type of hardware IP (SMU, GFX, UVD, etc.) - * - * Check if the hardware IP is enable or not. - * Returns true if it the IP is enable, false if not. - */ -bool amdgpu_device_ip_is_hw(struct amdgpu_device *adev, - enum amd_ip_block_type block_type) -{ - struct amdgpu_ip_block *ip_block; - - ip_block = amdgpu_device_ip_get_ip_block(adev, block_type); - if (ip_block) - return ip_block->status.hw; - - return false; -} - /** * amdgpu_device_ip_is_valid - is the hardware IP valid * @@ -409,3 +388,133 @@ bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev, return false; } + +/** + * amdgpu_ip_from_ring() - Find IP block type corresponding to ring type. + * + * @ring_type: The ring type whose IP block you are looking for. + */ +static enum amd_ip_block_type amdgpu_ip_from_ring(const enum amdgpu_ring_type ring_type) +{ + switch (ring_type) { + case AMDGPU_RING_TYPE_GFX: + case AMDGPU_RING_TYPE_COMPUTE: + return AMD_IP_BLOCK_TYPE_GFX; + + case AMDGPU_RING_TYPE_SDMA: + return AMD_IP_BLOCK_TYPE_SDMA; + + case AMDGPU_RING_TYPE_UVD: + case AMDGPU_RING_TYPE_UVD_ENC: + return AMD_IP_BLOCK_TYPE_UVD; + + case AMDGPU_RING_TYPE_VCE: + return AMD_IP_BLOCK_TYPE_VCE; + + case AMDGPU_RING_TYPE_VCN_DEC: + case AMDGPU_RING_TYPE_VCN_ENC: + return AMD_IP_BLOCK_TYPE_VCN; + + case AMDGPU_RING_TYPE_VCN_JPEG: + return AMD_IP_BLOCK_TYPE_JPEG; + + case AMDGPU_RING_TYPE_VPE: + return AMD_IP_BLOCK_TYPE_VPE; + + default: + return AMD_IP_BLOCK_TYPE_NUM; + } +} + +/** + * amdgpu_ring_mask_from_ip() - Find mask of ring types corresponding to an IP block type. + * + * @ip_type: The IP block type whose rings you are looking for. + */ +static u32 amdgpu_ring_mask_from_ip(const enum amd_ip_block_type ip_type) +{ + switch (ip_type) { + case AMD_IP_BLOCK_TYPE_GFX: + return BIT(AMDGPU_RING_TYPE_GFX) | BIT(AMDGPU_RING_TYPE_COMPUTE); + + case AMD_IP_BLOCK_TYPE_SDMA: + return BIT(AMDGPU_RING_TYPE_SDMA); + + case AMD_IP_BLOCK_TYPE_UVD: + return BIT(AMDGPU_RING_TYPE_UVD) | BIT(AMDGPU_RING_TYPE_UVD_ENC); + + case AMD_IP_BLOCK_TYPE_VCE: + return BIT(AMD_IP_BLOCK_TYPE_VCE); + + case AMD_IP_BLOCK_TYPE_VCN: + return BIT(AMDGPU_RING_TYPE_VCN_DEC) | BIT(AMDGPU_RING_TYPE_VCN_ENC); + + case AMD_IP_BLOCK_TYPE_JPEG: + return BIT(AMDGPU_RING_TYPE_VCN_JPEG); + + case AMD_IP_BLOCK_TYPE_VPE: + return BIT(AMDGPU_RING_TYPE_VPE); + + default: + return 0; + } +} + +/** + * amdgpu_device_ip_soft_reset() - Perform a graceful soft reset on an IP block. + * + * @guilty_ring: The ring which is guilty of causing a reset. + * @guilty_fence: The fence which didn't signal. + * + * IP block soft reset is used when attempting to recover + * from a GPU hang in a situation where a more fine grained + * reset type isn't available or didn't work. This effectively + * resets all rings that belong to the same device IP block + * and re-initializes the device IP block. + * + * The reset is handled gracefully, meaning that we try to + * minimize collateral damage (ie. avoid rejecting non-guilty jobs) + * as well as back up and restore the contents of all rings + * so that the system can move on from the hang. + */ +int amdgpu_device_ip_soft_reset(struct amdgpu_ring *guilty_ring, + struct amdgpu_fence *guilty_fence) +{ + struct amdgpu_device *adev = guilty_ring->adev; + struct amdgpu_ip_block *ip_block; + enum amd_ip_block_type ip_type; + u32 ring_type_mask; + int r; + + ip_type = amdgpu_ip_from_ring(guilty_ring->funcs->type); + ip_block = amdgpu_device_ip_get_ip_block(adev, ip_type); + + if (!ip_block || !ip_block->version->funcs->soft_reset) { + dev_warn(adev->dev, "IP block soft reset not supported on %s\n", + ip_block->version->funcs->name); + return -EOPNOTSUPP; + } + + dev_err(adev->dev, "Starting %s IP block soft reset\n", + ip_block->version->funcs->name); + + ring_type_mask = amdgpu_ring_mask_from_ip(ip_type); + + amdgpu_device_lock_reset_domain(adev->reset_domain); + amdgpu_multi_ring_reset_helper_begin(ring_type_mask, guilty_ring, guilty_fence); + + r = ip_block->version->funcs->soft_reset(ip_block); + + r = amdgpu_multi_ring_reset_helper_end(ring_type_mask, guilty_ring, r); + amdgpu_device_unlock_reset_domain(adev->reset_domain); + + if (r) { + dev_err(adev->dev, "Failed %s IP block soft reset: %d\n", + ip_block->version->funcs->name, r); + return r; + } + + dev_err(adev->dev, "Successful %s IP block soft reset\n", + ip_block->version->funcs->name); + return 0; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h index 1d0df6d93957..70fc4e5db51f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ip.h @@ -68,6 +68,7 @@ enum amd_hw_ip_block_type { ISP_HWIP, ATU_HWIP, AIGC_HWIP, + UMSCH_HWIP, MAX_HWIP }; @@ -84,6 +85,9 @@ enum amd_hw_ip_block_type { #define IP_VERSION_SUBREV(ver) ((ver) & 0xF) #define IP_VERSION_MAJ_MIN_REV(ver) ((ver) >> 8) +struct amdgpu_ring; +struct amdgpu_fence; + struct amdgpu_ip_map_info { /* Map of logical to actual dev instances/mask */ uint32_t dev_inst[MAX_HWIP][HWIP_MAX_INSTANCE]; @@ -146,9 +150,9 @@ void amdgpu_device_ip_get_clockgating_state(struct amdgpu_device *adev, u64 *flags); int amdgpu_device_ip_wait_for_idle(struct amdgpu_device *adev, enum amd_ip_block_type block_type); -bool amdgpu_device_ip_is_hw(struct amdgpu_device *adev, - enum amd_ip_block_type block_type); bool amdgpu_device_ip_is_valid(struct amdgpu_device *adev, enum amd_ip_block_type block_type); +int amdgpu_device_ip_soft_reset(struct amdgpu_ring *guilty_ring, + struct amdgpu_fence *guilty_fence); #endif /* __AMDGPU_IP_H__ */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c index 9ecc6387c1eb..cff73f1b5a72 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c @@ -112,7 +112,7 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) amdgpu_job_core_dump(adev, job); if (amdgpu_gpu_recovery && - amdgpu_ring_is_reset_type_supported(ring, AMDGPU_RESET_TYPE_SOFT_RESET) && + amdgpu_ring_is_reset_type_supported(ring, AMDGPU_RESET_TYPE_SOFT_RECOVERY) && amdgpu_ring_soft_recovery(ring, job->vmid, s_job->s_fence->parent)) { dev_err(adev->dev, "ring %s timeout, but soft recovered\n", s_job->sched->name); @@ -151,6 +151,17 @@ static enum drm_gpu_sched_stat amdgpu_job_timedout(struct drm_sched_job *s_job) dev_err(adev->dev, "Ring %s reset failed\n", ring->sched.name); } + /* Attempt an IP block soft reset, if supported. */ + if (amdgpu_gpu_recovery && + amdgpu_ring_is_reset_type_supported(ring, AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET)) { + r = amdgpu_device_ip_soft_reset(ring, job->hw_fence); + if (!r) { + atomic_inc(&ring->adev->gpu_reset_counter); + drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, info); + goto exit; + } + } + if (dma_fence_get_status(&s_job->s_fence->finished) == 0) dma_fence_set_error(&s_job->s_fence->finished, -ETIME); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c index 63ee6ba6a931..57935c321515 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c @@ -134,8 +134,8 @@ void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; - atomic_inc(&adev->jpeg.total_submission_cnt); - cancel_delayed_work_sync(&adev->jpeg.idle_work); + if (!atomic_fetch_inc(&adev->jpeg.total_submission_cnt)) + cancel_delayed_work_sync(&adev->jpeg.idle_work); mutex_lock(&adev->jpeg.jpeg_pg_lock); amdgpu_device_ip_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_JPEG, @@ -145,8 +145,9 @@ void amdgpu_jpeg_ring_begin_use(struct amdgpu_ring *ring) void amdgpu_jpeg_ring_end_use(struct amdgpu_ring *ring) { - atomic_dec(&ring->adev->jpeg.total_submission_cnt); - schedule_delayed_work(&ring->adev->jpeg.idle_work, JPEG_IDLE_TIMEOUT); + if (atomic_dec_and_test(&ring->adev->jpeg.total_submission_cnt)) + schedule_delayed_work(&ring->adev->jpeg.idle_work, + JPEG_IDLE_TIMEOUT); } int amdgpu_jpeg_dec_ring_test_ring(struct amdgpu_ring *ring) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h index 346ae0ab09d3..fe95d9188713 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h @@ -149,6 +149,9 @@ struct amdgpu_jpeg { u32 *ip_dump; u32 reg_count; const struct amdgpu_hwip_reg_entry *reg_list; + + bool disable_uq; + bool disable_kq; }; int amdgpu_jpeg_sw_init(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 71272f40feef..215aa678d1d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -1423,6 +1423,33 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) return 0; } +/** + * amdgpu_proc_options_ioctl - set per-fd user options + * + * @dev: drm dev pointer + * @data: pointer to struct drm_amdgpu_proc_options + * @filp: drm file + * + * Sets options stored on the per-file amdgpu_fpriv. Currently the only + * supported option is %AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY which + * controls how KFD delivers SIGBUS for poison/RAS events to the calling + * process (immediate, suppressed, or delayed by N milliseconds). + */ +int amdgpu_proc_options_ioctl(struct drm_device *dev, void *data, + struct drm_file *filp) +{ + struct drm_amdgpu_proc_options *args = data; + + switch (args->op) { + case AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY: + return amdgpu_amdkfd_set_sigbus_delay(current, + args->kfd_sigbus_delay.value); + default: + DRM_DEBUG_KMS("Invalid user option op %u\n", args->op); + return -EINVAL; + } +} + /** * amdgpu_driver_open_kms - drm callback for open * @@ -1504,8 +1531,7 @@ int amdgpu_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) if (r) goto error_vm; - mutex_init(&fpriv->bo_list_lock); - idr_init_base(&fpriv->bo_list_handles, 1); + xa_init_flags(&fpriv->bo_list_handles, XA_FLAGS_ALLOC1); r = amdgpu_userq_mgr_init(&fpriv->userq_mgr, file_priv, adev); if (r) @@ -1550,8 +1576,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, struct amdgpu_fpriv *fpriv = file_priv->driver_priv; struct amdgpu_bo_list *list; struct amdgpu_bo *pd; + unsigned long handle; u32 pasid; - int handle; if (!fpriv) return; @@ -1587,11 +1613,9 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, amdgpu_pasid_free_delayed(pd->tbo.base.resv, pasid); amdgpu_bo_unref(&pd); - idr_for_each_entry(&fpriv->bo_list_handles, list, handle) + xa_for_each(&fpriv->bo_list_handles, handle, list) amdgpu_bo_list_put(list); - - idr_destroy(&fpriv->bo_list_handles); - mutex_destroy(&fpriv->bo_list_lock); + xa_destroy(&fpriv->bo_list_handles); kfree(fpriv); file_priv->driver_priv = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c index cc6d1a4e4c3a..9a7f7d2b2767 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.c @@ -27,16 +27,6 @@ #include "umc/umc_6_7_0_offset.h" #include "umc/umc_6_7_0_sh_mask.h" -static bool amdgpu_mca_is_deferred_error(struct amdgpu_device *adev, - uint64_t mc_status) -{ - if (adev->umc.ras->check_ecc_err_status) - return adev->umc.ras->check_ecc_err_status(adev, - AMDGPU_MCA_ERROR_TYPE_DE, &mc_status); - - return false; -} - void amdgpu_mca_query_correctable_error_count(struct amdgpu_device *adev, uint64_t mc_status_addr, unsigned long *error_count) @@ -155,479 +145,3 @@ int amdgpu_mca_mpio_ras_sw_init(struct amdgpu_device *adev) return 0; } - -static void amdgpu_mca_bank_set_init(struct mca_bank_set *mca_set) -{ - if (!mca_set) - return; - - memset(mca_set, 0, sizeof(*mca_set)); - INIT_LIST_HEAD(&mca_set->list); -} - -static int amdgpu_mca_bank_set_add_entry(struct mca_bank_set *mca_set, struct mca_bank_entry *entry) -{ - struct mca_bank_node *node; - - if (!entry) - return -EINVAL; - - node = kvzalloc_obj(*node); - if (!node) - return -ENOMEM; - - memcpy(&node->entry, entry, sizeof(*entry)); - - INIT_LIST_HEAD(&node->node); - list_add_tail(&node->node, &mca_set->list); - - mca_set->nr_entries++; - - return 0; -} - -static int amdgpu_mca_bank_set_merge(struct mca_bank_set *mca_set, struct mca_bank_set *new) -{ - struct mca_bank_node *node; - - list_for_each_entry(node, &new->list, node) - amdgpu_mca_bank_set_add_entry(mca_set, &node->entry); - - return 0; -} - -static void amdgpu_mca_bank_set_remove_node(struct mca_bank_set *mca_set, struct mca_bank_node *node) -{ - if (!node) - return; - - list_del(&node->node); - kvfree(node); - - mca_set->nr_entries--; -} - -static void amdgpu_mca_bank_set_release(struct mca_bank_set *mca_set) -{ - struct mca_bank_node *node, *tmp; - - if (list_empty(&mca_set->list)) - return; - - list_for_each_entry_safe(node, tmp, &mca_set->list, node) - amdgpu_mca_bank_set_remove_node(mca_set, node); -} - -void amdgpu_mca_smu_init_funcs(struct amdgpu_device *adev, const struct amdgpu_mca_smu_funcs *mca_funcs) -{ - struct amdgpu_mca *mca = &adev->mca; - - mca->mca_funcs = mca_funcs; -} - -int amdgpu_mca_init(struct amdgpu_device *adev) -{ - struct amdgpu_mca *mca = &adev->mca; - struct mca_bank_cache *mca_cache; - int i; - - atomic_set(&mca->ue_update_flag, 0); - - for (i = 0; i < ARRAY_SIZE(mca->mca_caches); i++) { - mca_cache = &mca->mca_caches[i]; - mutex_init(&mca_cache->lock); - amdgpu_mca_bank_set_init(&mca_cache->mca_set); - } - - return 0; -} - -void amdgpu_mca_fini(struct amdgpu_device *adev) -{ - struct amdgpu_mca *mca = &adev->mca; - struct mca_bank_cache *mca_cache; - int i; - - atomic_set(&mca->ue_update_flag, 0); - - for (i = 0; i < ARRAY_SIZE(mca->mca_caches); i++) { - mca_cache = &mca->mca_caches[i]; - amdgpu_mca_bank_set_release(&mca_cache->mca_set); - mutex_destroy(&mca_cache->lock); - } -} - -int amdgpu_mca_reset(struct amdgpu_device *adev) -{ - amdgpu_mca_fini(adev); - - return amdgpu_mca_init(adev); -} - -int amdgpu_mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) -{ - const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; - - if (mca_funcs && mca_funcs->mca_set_debug_mode) - return mca_funcs->mca_set_debug_mode(adev, enable); - - return -EOPNOTSUPP; -} - -static void amdgpu_mca_smu_mca_bank_dump(struct amdgpu_device *adev, int idx, struct mca_bank_entry *entry, - struct ras_query_context *qctx) -{ - u64 event_id = qctx ? qctx->evid.event_id : RAS_EVENT_INVALID_ID; - - RAS_EVENT_LOG(adev, event_id, HW_ERR "Accelerator Check Architecture events logged\n"); - RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].STATUS=0x%016llx\n", - idx, entry->regs[MCA_REG_IDX_STATUS]); - RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].ADDR=0x%016llx\n", - idx, entry->regs[MCA_REG_IDX_ADDR]); - RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].MISC0=0x%016llx\n", - idx, entry->regs[MCA_REG_IDX_MISC0]); - RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].IPID=0x%016llx\n", - idx, entry->regs[MCA_REG_IDX_IPID]); - RAS_EVENT_LOG(adev, event_id, HW_ERR "aca entry[%02d].SYND=0x%016llx\n", - idx, entry->regs[MCA_REG_IDX_SYND]); -} - -static int amdgpu_mca_smu_get_valid_mca_count(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, uint32_t *count) -{ - const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; - - if (!count) - return -EINVAL; - - if (mca_funcs && mca_funcs->mca_get_valid_mca_count) - return mca_funcs->mca_get_valid_mca_count(adev, type, count); - - return -EOPNOTSUPP; -} - -static int amdgpu_mca_smu_get_mca_entry(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, - int idx, struct mca_bank_entry *entry) -{ - const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; - int count; - - if (!mca_funcs || !mca_funcs->mca_get_mca_entry) - return -EOPNOTSUPP; - - switch (type) { - case AMDGPU_MCA_ERROR_TYPE_UE: - count = mca_funcs->max_ue_count; - break; - case AMDGPU_MCA_ERROR_TYPE_CE: - count = mca_funcs->max_ce_count; - break; - default: - return -EINVAL; - } - - if (idx >= count) - return -EINVAL; - - return mca_funcs->mca_get_mca_entry(adev, type, idx, entry); -} - -static bool amdgpu_mca_bank_should_update(struct amdgpu_device *adev, enum amdgpu_mca_error_type type) -{ - struct amdgpu_mca *mca = &adev->mca; - bool ret = true; - - /* - * Because the UE Valid MCA count will only be cleared after reset, - * in order to avoid repeated counting of the error count, - * the aca bank is only updated once during the gpu recovery stage. - */ - if (type == AMDGPU_MCA_ERROR_TYPE_UE) { - if (amdgpu_ras_intr_triggered()) - ret = atomic_cmpxchg(&mca->ue_update_flag, 0, 1) == 0; - else - atomic_set(&mca->ue_update_flag, 0); - } - - return ret; -} - -static bool amdgpu_mca_bank_should_dump(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, - struct mca_bank_entry *entry) -{ - bool ret; - - switch (type) { - case AMDGPU_MCA_ERROR_TYPE_CE: - ret = amdgpu_mca_is_deferred_error(adev, entry->regs[MCA_REG_IDX_STATUS]); - break; - case AMDGPU_MCA_ERROR_TYPE_UE: - default: - ret = true; - break; - } - - return ret; -} - -static int amdgpu_mca_smu_get_mca_set(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, struct mca_bank_set *mca_set, - struct ras_query_context *qctx) -{ - struct mca_bank_entry entry; - uint32_t count = 0, i; - int ret; - - if (!mca_set) - return -EINVAL; - - if (!amdgpu_mca_bank_should_update(adev, type)) - return 0; - - ret = amdgpu_mca_smu_get_valid_mca_count(adev, type, &count); - if (ret) - return ret; - - for (i = 0; i < count; i++) { - memset(&entry, 0, sizeof(entry)); - ret = amdgpu_mca_smu_get_mca_entry(adev, type, i, &entry); - if (ret) - return ret; - - amdgpu_mca_bank_set_add_entry(mca_set, &entry); - - if (amdgpu_mca_bank_should_dump(adev, type, &entry)) - amdgpu_mca_smu_mca_bank_dump(adev, i, &entry, qctx); - } - - return 0; -} - -static int amdgpu_mca_smu_parse_mca_error_count(struct amdgpu_device *adev, enum amdgpu_ras_block blk, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count) -{ - const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; - - if (!count || !entry) - return -EINVAL; - - if (!mca_funcs || !mca_funcs->mca_parse_mca_error_count) - return -EOPNOTSUPP; - - return mca_funcs->mca_parse_mca_error_count(adev, blk, type, entry, count); -} - -static int amdgpu_mca_dispatch_mca_set(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type, - struct mca_bank_set *mca_set, struct ras_err_data *err_data) -{ - struct amdgpu_smuio_mcm_config_info mcm_info; - struct mca_bank_node *node, *tmp; - struct mca_bank_entry *entry; - uint32_t count; - int ret; - - if (!mca_set) - return -EINVAL; - - if (!mca_set->nr_entries) - return 0; - - list_for_each_entry_safe(node, tmp, &mca_set->list, node) { - entry = &node->entry; - - count = 0; - ret = amdgpu_mca_smu_parse_mca_error_count(adev, blk, type, entry, &count); - if (ret && ret != -EOPNOTSUPP) - return ret; - - if (!count) - continue; - - memset(&mcm_info, 0, sizeof(mcm_info)); - - mcm_info.socket_id = entry->info.socket_id; - mcm_info.die_id = entry->info.aid; - - if (type == AMDGPU_MCA_ERROR_TYPE_UE) { - amdgpu_ras_error_statistic_ue_count(err_data, - &mcm_info, (uint64_t)count); - } else { - if (amdgpu_mca_is_deferred_error(adev, entry->regs[MCA_REG_IDX_STATUS])) - amdgpu_ras_error_statistic_de_count(err_data, - &mcm_info, (uint64_t)count); - else - amdgpu_ras_error_statistic_ce_count(err_data, - &mcm_info, (uint64_t)count); - } - - amdgpu_mca_bank_set_remove_node(mca_set, node); - } - - return 0; -} - -static int amdgpu_mca_add_mca_set_to_cache(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, struct mca_bank_set *new) -{ - struct mca_bank_cache *mca_cache = &adev->mca.mca_caches[type]; - int ret; - - mutex_lock(&mca_cache->lock); - ret = amdgpu_mca_bank_set_merge(&mca_cache->mca_set, new); - mutex_unlock(&mca_cache->lock); - - return ret; -} - -int amdgpu_mca_smu_log_ras_error(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type, - struct ras_err_data *err_data, struct ras_query_context *qctx) -{ - struct mca_bank_set mca_set; - struct mca_bank_cache *mca_cache = &adev->mca.mca_caches[type]; - int ret; - - amdgpu_mca_bank_set_init(&mca_set); - - ret = amdgpu_mca_smu_get_mca_set(adev, type, &mca_set, qctx); - if (ret) - goto out_mca_release; - - ret = amdgpu_mca_dispatch_mca_set(adev, blk, type, &mca_set, err_data); - if (ret) - goto out_mca_release; - - /* add remain mca bank to mca cache */ - if (mca_set.nr_entries) { - ret = amdgpu_mca_add_mca_set_to_cache(adev, type, &mca_set); - if (ret) - goto out_mca_release; - } - - /* dispatch mca set again if mca cache has valid data */ - mutex_lock(&mca_cache->lock); - if (mca_cache->mca_set.nr_entries) - ret = amdgpu_mca_dispatch_mca_set(adev, blk, type, &mca_cache->mca_set, err_data); - mutex_unlock(&mca_cache->lock); - -out_mca_release: - amdgpu_mca_bank_set_release(&mca_set); - - return ret; -} - -#if defined(CONFIG_DEBUG_FS) -static int amdgpu_mca_smu_debug_mode_set(void *data, u64 val) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)data; - int ret; - - ret = amdgpu_ras_set_mca_debug_mode(adev, val ? true : false); - if (ret) - return ret; - - dev_info(adev->dev, "amdgpu set smu mca debug mode %s success\n", val ? "on" : "off"); - - return 0; -} - -static void mca_dump_entry(struct seq_file *m, struct mca_bank_entry *entry) -{ - int i, idx = entry->idx; - int reg_idx_array[] = { - MCA_REG_IDX_STATUS, - MCA_REG_IDX_ADDR, - MCA_REG_IDX_MISC0, - MCA_REG_IDX_IPID, - MCA_REG_IDX_SYND, - }; - - seq_printf(m, "mca entry[%d].type: %s\n", idx, entry->type == AMDGPU_MCA_ERROR_TYPE_UE ? "UE" : "CE"); - seq_printf(m, "mca entry[%d].ip: %d\n", idx, entry->ip); - seq_printf(m, "mca entry[%d].info: socketid:%d aid:%d hwid:0x%03x mcatype:0x%04x\n", - idx, entry->info.socket_id, entry->info.aid, entry->info.hwid, entry->info.mcatype); - - for (i = 0; i < ARRAY_SIZE(reg_idx_array); i++) - seq_printf(m, "mca entry[%d].regs[%d]: 0x%016llx\n", idx, reg_idx_array[i], entry->regs[reg_idx_array[i]]); -} - -static int mca_dump_show(struct seq_file *m, enum amdgpu_mca_error_type type) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)m->private; - struct mca_bank_node *node; - struct mca_bank_set mca_set; - struct ras_query_context qctx; - int ret; - - amdgpu_mca_bank_set_init(&mca_set); - - qctx.evid.event_id = RAS_EVENT_INVALID_ID; - ret = amdgpu_mca_smu_get_mca_set(adev, type, &mca_set, &qctx); - if (ret) - goto err_free_mca_set; - - seq_printf(m, "amdgpu smu %s valid mca count: %d\n", - type == AMDGPU_MCA_ERROR_TYPE_UE ? "UE" : "CE", mca_set.nr_entries); - - if (!mca_set.nr_entries) - goto err_free_mca_set; - - list_for_each_entry(node, &mca_set.list, node) - mca_dump_entry(m, &node->entry); - - /* add mca bank to mca bank cache */ - ret = amdgpu_mca_add_mca_set_to_cache(adev, type, &mca_set); - -err_free_mca_set: - amdgpu_mca_bank_set_release(&mca_set); - - return ret; -} - -static int mca_dump_ce_show(struct seq_file *m, void *unused) -{ - return mca_dump_show(m, AMDGPU_MCA_ERROR_TYPE_CE); -} - -static int mca_dump_ce_open(struct inode *inode, struct file *file) -{ - return single_open(file, mca_dump_ce_show, inode->i_private); -} - -static const struct file_operations mca_ce_dump_debug_fops = { - .owner = THIS_MODULE, - .open = mca_dump_ce_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int mca_dump_ue_show(struct seq_file *m, void *unused) -{ - return mca_dump_show(m, AMDGPU_MCA_ERROR_TYPE_UE); -} - -static int mca_dump_ue_open(struct inode *inode, struct file *file) -{ - return single_open(file, mca_dump_ue_show, inode->i_private); -} - -static const struct file_operations mca_ue_dump_debug_fops = { - .owner = THIS_MODULE, - .open = mca_dump_ue_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -DEFINE_DEBUGFS_ATTRIBUTE(mca_debug_mode_fops, NULL, amdgpu_mca_smu_debug_mode_set, "%llu\n"); -#endif - -void amdgpu_mca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root) -{ -#if defined(CONFIG_DEBUG_FS) - if (!root) - return; - - debugfs_create_file("mca_debug_mode", 0200, root, adev, &mca_debug_mode_fops); - debugfs_create_file("mca_ue_dump", 0400, root, adev, &mca_ue_dump_debug_fops); - debugfs_create_file("mca_ce_dump", 0400, root, adev, &mca_ce_dump_debug_fops); -#endif -} - diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h index e80323ff90c1..6d12f8a516d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mca.h @@ -23,45 +23,6 @@ #include "amdgpu_ras.h" -#define MCA_MAX_REGS_COUNT (16) - -#define MCA_REG_FIELD(x, h, l) (((x) & GENMASK_ULL(h, l)) >> l) -#define MCA_REG__STATUS__VAL(x) MCA_REG_FIELD(x, 63, 63) -#define MCA_REG__STATUS__OVERFLOW(x) MCA_REG_FIELD(x, 62, 62) -#define MCA_REG__STATUS__UC(x) MCA_REG_FIELD(x, 61, 61) -#define MCA_REG__STATUS__EN(x) MCA_REG_FIELD(x, 60, 60) -#define MCA_REG__STATUS__MISCV(x) MCA_REG_FIELD(x, 59, 59) -#define MCA_REG__STATUS__ADDRV(x) MCA_REG_FIELD(x, 58, 58) -#define MCA_REG__STATUS__PCC(x) MCA_REG_FIELD(x, 57, 57) -#define MCA_REG__STATUS__ERRCOREIDVAL(x) MCA_REG_FIELD(x, 56, 56) -#define MCA_REG__STATUS__TCC(x) MCA_REG_FIELD(x, 55, 55) -#define MCA_REG__STATUS__SYNDV(x) MCA_REG_FIELD(x, 53, 53) -#define MCA_REG__STATUS__CECC(x) MCA_REG_FIELD(x, 46, 46) -#define MCA_REG__STATUS__UECC(x) MCA_REG_FIELD(x, 45, 45) -#define MCA_REG__STATUS__DEFERRED(x) MCA_REG_FIELD(x, 44, 44) -#define MCA_REG__STATUS__POISON(x) MCA_REG_FIELD(x, 43, 43) -#define MCA_REG__STATUS__SCRUB(x) MCA_REG_FIELD(x, 40, 40) -#define MCA_REG__STATUS__ERRCOREID(x) MCA_REG_FIELD(x, 37, 32) -#define MCA_REG__STATUS__ADDRLSB(x) MCA_REG_FIELD(x, 29, 24) -#define MCA_REG__STATUS__ERRORCODEEXT(x) MCA_REG_FIELD(x, 21, 16) -#define MCA_REG__STATUS__ERRORCODE(x) MCA_REG_FIELD(x, 15, 0) - -#define MCA_REG__MISC0__ERRCNT(x) MCA_REG_FIELD(x, 43, 32) - -#define MCA_REG__SYND__ERRORINFORMATION(x) MCA_REG_FIELD(x, 17, 0) - -enum amdgpu_mca_ip { - AMDGPU_MCA_IP_UNKNOW = -1, - AMDGPU_MCA_IP_PSP = 0, - AMDGPU_MCA_IP_SDMA, - AMDGPU_MCA_IP_GC, - AMDGPU_MCA_IP_SMU, - AMDGPU_MCA_IP_MP5, - AMDGPU_MCA_IP_UMC, - AMDGPU_MCA_IP_PCS_XGMI, - AMDGPU_MCA_IP_COUNT, -}; - enum amdgpu_mca_error_type { AMDGPU_MCA_ERROR_TYPE_UE = 0, AMDGPU_MCA_ERROR_TYPE_CE, @@ -77,77 +38,20 @@ struct amdgpu_mca_ras { struct amdgpu_mca_ras_block *ras; }; -struct mca_bank_set { - int nr_entries; - struct list_head list; -}; - -struct mca_bank_cache { - struct mca_bank_set mca_set; - struct mutex lock; -}; - struct amdgpu_mca { struct amdgpu_mca_ras mp0; struct amdgpu_mca_ras mp1; struct amdgpu_mca_ras mpio; - const struct amdgpu_mca_smu_funcs *mca_funcs; - struct mca_bank_cache mca_caches[AMDGPU_MCA_ERROR_TYPE_DE]; - atomic_t ue_update_flag; -}; - -enum mca_reg_idx { - MCA_REG_IDX_STATUS = 1, - MCA_REG_IDX_ADDR = 2, - MCA_REG_IDX_MISC0 = 3, - MCA_REG_IDX_IPID = 5, - MCA_REG_IDX_SYND = 6, - MCA_REG_IDX_COUNT = 16, -}; - -struct mca_bank_info { - int socket_id; - int aid; - int hwid; - int mcatype; -}; - -struct mca_bank_entry { - int idx; - enum amdgpu_mca_error_type type; - enum amdgpu_mca_ip ip; - struct mca_bank_info info; - uint64_t regs[MCA_MAX_REGS_COUNT]; -}; - -struct mca_bank_node { - struct mca_bank_entry entry; - struct list_head node; -}; - -struct amdgpu_mca_smu_funcs { - int max_ue_count; - int max_ce_count; - int (*mca_set_debug_mode)(struct amdgpu_device *adev, bool enable); - int (*mca_parse_mca_error_count)(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type, - struct mca_bank_entry *entry, uint32_t *count); - int (*mca_get_valid_mca_count)(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, - uint32_t *count); - int (*mca_get_mca_entry)(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, - int idx, struct mca_bank_entry *entry); }; void amdgpu_mca_query_correctable_error_count(struct amdgpu_device *adev, uint64_t mc_status_addr, unsigned long *error_count); - void amdgpu_mca_query_uncorrectable_error_count(struct amdgpu_device *adev, uint64_t mc_status_addr, unsigned long *error_count); - void amdgpu_mca_reset_error_count(struct amdgpu_device *adev, uint64_t mc_status_addr); - void amdgpu_mca_query_ras_error_count(struct amdgpu_device *adev, uint64_t mc_status_addr, void *ras_error_status); @@ -155,15 +59,4 @@ int amdgpu_mca_mp0_ras_sw_init(struct amdgpu_device *adev); int amdgpu_mca_mp1_ras_sw_init(struct amdgpu_device *adev); int amdgpu_mca_mpio_ras_sw_init(struct amdgpu_device *adev); -void amdgpu_mca_smu_init_funcs(struct amdgpu_device *adev, const struct amdgpu_mca_smu_funcs *mca_funcs); -int amdgpu_mca_init(struct amdgpu_device *adev); -void amdgpu_mca_fini(struct amdgpu_device *adev); -int amdgpu_mca_reset(struct amdgpu_device *adev); -int amdgpu_mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable); -int amdgpu_mca_smu_get_mca_set_error_count(struct amdgpu_device *adev, enum amdgpu_ras_block blk, - enum amdgpu_mca_error_type type, uint32_t *total); -void amdgpu_mca_smu_debugfs_init(struct amdgpu_device *adev, struct dentry *root); -int amdgpu_mca_smu_log_ras_error(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type, - struct ras_err_data *err_data, struct ras_query_context *qctx); - #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c index e3972673fd64..6c0dde3786e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.c @@ -217,7 +217,7 @@ int amdgpu_mes_init(struct amdgpu_device *adev) if (r) goto error_doorbell; - if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(12, 1, 0)) { + if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(11, 0, 0)) { /* When queue/pipe reset is done in MES instead of in the * driver, MES passes hung queues information to the driver in * hung_queue_hqd_info. Calculate required space to store this @@ -252,6 +252,10 @@ int amdgpu_mes_init(struct amdgpu_device *adev) } } + adev->gfx.mec.mes_hung_db_array = + kcalloc(amdgpu_mes_get_hung_queue_db_array_size(adev), + sizeof(u32), GFP_KERNEL); + return 0; error_doorbell: @@ -279,6 +283,8 @@ void amdgpu_mes_fini(struct amdgpu_device *adev) int i; int num_xcc = adev->gfx.xcc_mask ? NUM_XCC(adev->gfx.xcc_mask) : 1; + kfree(adev->gfx.mec.mes_hung_db_array); + amdgpu_bo_free_kernel(&adev->mes.event_log_gpu_obj, &adev->mes.event_log_gpu_addr, &adev->mes.event_log_cpu_addr); @@ -439,6 +445,59 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev, return r; } +int amdgpu_mes_reset_queue_mmio(struct amdgpu_device *adev, + int queue_type, + unsigned int vmid, + unsigned int me, + unsigned int pipe, + unsigned int queue, + uint32_t xcc_id) +{ + struct mes_reset_queue_input queue_input; + int r; + + memset(&queue_input, 0, sizeof(queue_input)); + + queue_input.xcc_id = xcc_id; + queue_input.me_id = me; + queue_input.pipe_id = pipe; + queue_input.queue_id = queue; + queue_input.vmid = vmid; + queue_input.queue_type = queue_type; + queue_input.use_mmio = true; + + amdgpu_mes_lock(&adev->mes); + r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input); + amdgpu_mes_unlock(&adev->mes); + if (r) + dev_err(adev->dev, "failed to reset legacy queue\n"); + + return r; +} + +int amdgpu_mes_reset_user_queue(struct amdgpu_device *adev, + int queue_type, + unsigned int doorbell_index, + unsigned int xcc_id) +{ + struct mes_reset_queue_input queue_input; + int r; + + memset(&queue_input, 0, sizeof(queue_input)); + + queue_input.xcc_id = xcc_id; + queue_input.queue_type = queue_type; + queue_input.doorbell_offset = doorbell_index; + + amdgpu_mes_lock(&adev->mes); + r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input); + amdgpu_mes_unlock(&adev->mes); + if (r) + dev_err(adev->dev, "failed to reset user queue\n"); + + return r; +} + int amdgpu_mes_get_hung_queue_db_array_size(struct amdgpu_device *adev) { return adev->mes.hung_queue_db_array_size; @@ -805,8 +864,13 @@ bool amdgpu_mes_suspend_resume_all_supported(struct amdgpu_device *adev) bool amdgpu_mes_queue_reset_by_mes_supported(struct amdgpu_device *adev) { - return (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(12, 1, 0) && - (adev->mes.sched_version & AMDGPU_MES_VERSION_MASK) >= 0x73); + u32 ip_maj = IP_VERSION_MAJ(amdgpu_ip_version(adev, GC_HWIP, 0)); + u32 ip_min = IP_VERSION_MIN(amdgpu_ip_version(adev, GC_HWIP, 0)); + u32 mes_sched = adev->mes.sched_version & AMDGPU_MES_VERSION_MASK; + + return (ip_maj == 11 && mes_sched >= 0x8c) || + ((ip_maj == 12 && ip_min == 0) && mes_sched >= 0x8d) || + ((ip_maj == 12 && ip_min == 1) && mes_sched >= 0x73); } /* Fix me -- node_id is used to identify the correct MES instances in the future */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h index fdd06a17520a..f25cffad8efe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mes.h @@ -168,6 +168,9 @@ struct amdgpu_mes { int master_xcc_ids[AMDGPU_MAX_MES_INST_PIPES]; struct amdgpu_bo *shared_cmd_buf_obj[AMDGPU_MAX_MES_INST_PIPES]; uint64_t shared_cmd_buf_gpu_addr[AMDGPU_MAX_MES_INST_PIPES]; + + bool compute_pipe_reset_enabled; + bool gfx_pipe_reset_enabled; }; struct amdgpu_mes_hung_queue_hqd_info { @@ -271,6 +274,7 @@ struct mes_remove_queue_input { uint32_t xcc_id; uint32_t doorbell_offset; uint64_t gang_context_addr; + uint32_t queue_type; bool remove_queue_after_reset; }; @@ -302,12 +306,14 @@ struct mes_suspend_gang_input { uint64_t gang_context_addr; uint64_t suspend_fence_addr; uint32_t suspend_fence_value; + uint32_t doorbell_offset; }; struct mes_resume_gang_input { uint32_t xcc_id; bool resume_all_gangs; uint64_t gang_context_addr; + uint32_t doorbell_offset; }; struct mes_reset_queue_input { @@ -459,6 +465,17 @@ int amdgpu_mes_reset_legacy_queue(struct amdgpu_device *adev, unsigned int vmid, bool use_mmio, uint32_t xcc_id); +int amdgpu_mes_reset_queue_mmio(struct amdgpu_device *adev, + int queue_type, + unsigned int vmid, + unsigned int me, + unsigned int pipe, + unsigned int queue, + uint32_t xcc_id); +int amdgpu_mes_reset_user_queue(struct amdgpu_device *adev, + int queue_type, + unsigned int doorbell_index, + unsigned int xcc_id); int amdgpu_mes_get_hung_queue_db_array_size(struct amdgpu_device *adev); int amdgpu_mes_detect_and_reset_hung_queues(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h index 6b8214650e5d..c5120ba51e24 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mmhub.h @@ -21,29 +21,6 @@ #ifndef __AMDGPU_MMHUB_H__ #define __AMDGPU_MMHUB_H__ -enum amdgpu_mmhub_ras_memory_id { - AMDGPU_MMHUB_WGMI_PAGEMEM = 0, - AMDGPU_MMHUB_RGMI_PAGEMEM = 1, - AMDGPU_MMHUB_WDRAM_PAGEMEM = 2, - AMDGPU_MMHUB_RDRAM_PAGEMEM = 3, - AMDGPU_MMHUB_WIO_CMDMEM = 4, - AMDGPU_MMHUB_RIO_CMDMEM = 5, - AMDGPU_MMHUB_WGMI_CMDMEM = 6, - AMDGPU_MMHUB_RGMI_CMDMEM = 7, - AMDGPU_MMHUB_WDRAM_CMDMEM = 8, - AMDGPU_MMHUB_RDRAM_CMDMEM = 9, - AMDGPU_MMHUB_MAM_DMEM0 = 10, - AMDGPU_MMHUB_MAM_DMEM1 = 11, - AMDGPU_MMHUB_MAM_DMEM2 = 12, - AMDGPU_MMHUB_MAM_DMEM3 = 13, - AMDGPU_MMHUB_WRET_TAGMEM = 19, - AMDGPU_MMHUB_RRET_TAGMEM = 20, - AMDGPU_MMHUB_WIO_DATAMEM = 21, - AMDGPU_MMHUB_WGMI_DATAMEM = 22, - AMDGPU_MMHUB_WDRAM_DATAMEM = 23, - AMDGPU_MMHUB_MEMORY_BLOCK_LAST, -}; - struct amdgpu_mmhub_ras { struct amdgpu_ras_block_object ras_block; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 4d68732d6223..ff11a0903499 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -312,46 +312,6 @@ uint32_t amdgpu_bo_mem_stats_placement(struct amdgpu_bo *bo); uint32_t amdgpu_bo_get_preferred_domain(struct amdgpu_device *adev, uint32_t domain); -/* - * sub allocation - */ -static inline struct amdgpu_sa_manager * -to_amdgpu_sa_manager(struct drm_suballoc_manager *manager) -{ - return container_of(manager, struct amdgpu_sa_manager, base); -} - -static inline uint64_t amdgpu_sa_bo_gpu_addr(struct drm_suballoc *sa_bo) -{ - return to_amdgpu_sa_manager(sa_bo->manager)->gpu_addr + - drm_suballoc_soffset(sa_bo); -} - -static inline void *amdgpu_sa_bo_cpu_addr(struct drm_suballoc *sa_bo) -{ - return to_amdgpu_sa_manager(sa_bo->manager)->cpu_ptr + - drm_suballoc_soffset(sa_bo); -} - -int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager, - unsigned size, u32 align, u32 domain); -void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager); -int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev, - struct amdgpu_sa_manager *sa_manager); -int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, - struct drm_suballoc **sa_bo, - unsigned int size); -void amdgpu_sa_bo_free(struct drm_suballoc **sa_bo, - struct dma_fence *fence); -#if defined(CONFIG_DEBUG_FS) -void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager, - struct seq_file *m); -u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m); -#endif -void amdgpu_debugfs_sa_init(struct amdgpu_device *adev); - bool amdgpu_bo_support_uswc(u64 bo_flags); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c index b1dc33301d83..e8592970aaab 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_preempt_mgr.c @@ -46,6 +46,17 @@ static ssize_t mem_info_preempt_used_show(struct device *dev, static DEVICE_ATTR_RO(mem_info_preempt_used); +/** + * amdgpu_preempt_mgr_sysfs_fini - remove PREEMPT manager sysfs attributes + * + * @adev: amdgpu_device pointer + */ +void amdgpu_preempt_mgr_sysfs_fini(struct amdgpu_device *adev) +{ + if (adev->dev->kobj.sd) + device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used); +} + /** * amdgpu_preempt_mgr_new - allocate a new node * @@ -137,9 +148,6 @@ void amdgpu_preempt_mgr_fini(struct amdgpu_device *adev) if (ret) return; - if (adev->dev->kobj.sd) - device_remove_file(adev->dev, &dev_attr_mem_info_preempt_used); - ttm_resource_manager_cleanup(man); ttm_set_driver_manager(&adev->mman.bdev, AMDGPU_PL_PREEMPT, NULL); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c index 0d3c18f04ac3..8ae72c862d11 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_psp_ta.c @@ -166,7 +166,8 @@ static ssize_t ta_if_load_debugfs_write(struct file *fp, const char *buf, size_t if (ret) return -EFAULT; - if (ta_bin_len > PSP_1_MEG) + if (ta_bin_len < sizeof(struct common_firmware_header) || + ta_bin_len > PSP_1_MEG) return -EINVAL; copy_pos += sizeof(uint32_t); @@ -321,6 +322,8 @@ static ssize_t ta_if_invoke_debugfs_write(struct file *fp, const char *buf, size ret = copy_from_user((void *)&shared_buf_len, &buf[copy_pos], sizeof(uint32_t)); if (ret) return -EFAULT; + if (!shared_buf_len || shared_buf_len > PSP_1_MEG) + return -EINVAL; copy_pos += sizeof(uint32_t); shared_buf = memdup_user(&buf[copy_pos], shared_buf_len); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 764cd4950408..148bb4cb0a2d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -128,12 +128,6 @@ const char *get_ras_block_str(struct ras_common_if *ras_block) /* typical ECC bad page rate is 1 bad page per 100MB VRAM */ #define RAS_BAD_PAGE_COVER (100 * 1024 * 1024ULL) -#define MAX_UMC_POISON_POLLING_TIME_ASYNC 10 - -#define AMDGPU_RAS_RETIRE_PAGE_INTERVAL 100 //ms - -#define MAX_FLUSH_RETIRE_DWORK_TIMES 100 - #define BYPASS_ALLOCATED_ADDRESS 0x0 #define BYPASS_INITIALIZATION_ADDRESS 0x1 @@ -249,16 +243,12 @@ static int amdgpu_check_address_validity(struct amdgpu_device *adev, (address >= RAS_UMC_INJECT_ADDR_LIMIT)) return -EFAULT; - if (amdgpu_uniras_enabled(adev)) { - if (amdgpu_sriov_vf(adev)) - count = amdgpu_virt_ras_convert_retired_address(adev, address, - page_pfns, ARRAY_SIZE(page_pfns)); - else - count = amdgpu_ras_mgr_lookup_bad_pages_in_a_row(adev, address, - page_pfns, ARRAY_SIZE(page_pfns)); - } else - count = amdgpu_umc_lookup_bad_pages_in_a_row(adev, - address, page_pfns, ARRAY_SIZE(page_pfns)); + if (amdgpu_sriov_vf(adev)) + count = amdgpu_virt_ras_convert_retired_address(adev, address, + page_pfns, ARRAY_SIZE(page_pfns)); + else + count = amdgpu_ras_mgr_lookup_bad_pages_in_a_row(adev, address, + page_pfns, ARRAY_SIZE(page_pfns)); if (count <= 0) return -EPERM; @@ -1381,76 +1371,6 @@ static void amdgpu_ras_mgr_virt_error_data_statistics_update(struct ras_manager obj->err_data.de_count = err_data->de_count; } -static struct ras_manager *get_ras_manager(struct amdgpu_device *adev, enum amdgpu_ras_block blk) -{ - struct ras_common_if head; - - memset(&head, 0, sizeof(head)); - head.block = blk; - - return amdgpu_ras_find_obj(adev, &head); -} - -int amdgpu_ras_bind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk, - const struct aca_info *aca_info, void *data) -{ - struct ras_manager *obj; - - /* in resume phase, no need to create aca fs node */ - if (adev->in_suspend || amdgpu_reset_in_recovery(adev)) - return 0; - - obj = get_ras_manager(adev, blk); - if (!obj) - return -EINVAL; - - return amdgpu_aca_add_handle(adev, &obj->aca_handle, ras_block_str(blk), aca_info, data); -} - -int amdgpu_ras_unbind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk) -{ - struct ras_manager *obj; - - obj = get_ras_manager(adev, blk); - if (!obj) - return -EINVAL; - - amdgpu_aca_remove_handle(&obj->aca_handle); - - return 0; -} - -static int amdgpu_aca_log_ras_error_data(struct amdgpu_device *adev, enum amdgpu_ras_block blk, - enum aca_error_type type, struct ras_err_data *err_data, - struct ras_query_context *qctx) -{ - struct ras_manager *obj; - - obj = get_ras_manager(adev, blk); - if (!obj) - return -EINVAL; - - return amdgpu_aca_get_error_data(adev, &obj->aca_handle, type, err_data, qctx); -} - -ssize_t amdgpu_ras_aca_sysfs_read(struct device *dev, struct device_attribute *attr, - struct aca_handle *handle, char *buf, void *data) -{ - struct ras_manager *obj = container_of(handle, struct ras_manager, aca_handle); - struct ras_query_if info = { - .head = obj->head, - }; - - if (!amdgpu_ras_get_error_query_ready(obj->adev)) - return sysfs_emit(buf, "Query currently inaccessible\n"); - - if (amdgpu_ras_query_error_status(obj->adev, &info)) - return -EINVAL; - - return sysfs_emit(buf, "%s: %lu\n%s: %lu\n%s: %lu\n", "ue", info.ue_count, - "ce", info.ce_count, "de", info.de_count); -} - static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, struct ras_query_if *info, struct ras_err_data *err_data, @@ -1459,7 +1379,6 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, { enum amdgpu_ras_block blk = info ? info->head.block : AMDGPU_RAS_BLOCK_COUNT; struct amdgpu_ras_block_object *block_obj = NULL; - int ret; if (blk == AMDGPU_RAS_BLOCK_COUNT) return -EINVAL; @@ -1469,7 +1388,7 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, if (error_query_mode == AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY) { return amdgpu_virt_req_ras_err_count(adev, blk, err_data); - } else if (error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { + } else { if (info->head.block == AMDGPU_RAS_BLOCK__UMC) { amdgpu_ras_get_ecc_info(adev, err_data); } else { @@ -1490,24 +1409,6 @@ static int amdgpu_ras_query_error_status_helper(struct amdgpu_device *adev, block_obj->hw_ops->query_ras_error_status(adev); } } - } else { - if (amdgpu_aca_is_enabled(adev)) { - ret = amdgpu_aca_log_ras_error_data(adev, blk, ACA_ERROR_TYPE_UE, err_data, qctx); - if (ret) - return ret; - - ret = amdgpu_aca_log_ras_error_data(adev, blk, ACA_ERROR_TYPE_CE, err_data, qctx); - if (ret) - return ret; - - ret = amdgpu_aca_log_ras_error_data(adev, blk, ACA_ERROR_TYPE_DEFERRED, err_data, qctx); - if (ret) - return ret; - } else { - /* FIXME: add code to check return value later */ - amdgpu_mca_smu_log_ras_error(adev, blk, AMDGPU_MCA_ERROR_TYPE_UE, err_data, qctx); - amdgpu_mca_smu_log_ras_error(adev, blk, AMDGPU_MCA_ERROR_TYPE_CE, err_data, qctx); - } } return 0; @@ -1624,8 +1525,6 @@ int amdgpu_ras_reset_error_count(struct amdgpu_device *adev, enum amdgpu_ras_block block) { struct amdgpu_ras_block_object *block_obj = amdgpu_ras_get_ras_block(adev, block, 0); - const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; - const struct aca_smu_funcs *smu_funcs = adev->aca.smu_funcs; if (!block_obj || !block_obj->hw_ops) { dev_dbg_once(adev->dev, "%s doesn't config RAS function\n", @@ -1633,17 +1532,14 @@ int amdgpu_ras_reset_error_count(struct amdgpu_device *adev, return -EOPNOTSUPP; } - if (!amdgpu_ras_is_supported(adev, block) || - !amdgpu_ras_get_aca_debug_mode(adev)) + if (!amdgpu_ras_is_supported(adev, block)) return -EOPNOTSUPP; if (amdgpu_sriov_vf(adev)) return -EOPNOTSUPP; /* skip ras error reset in gpu reset */ - if ((amdgpu_in_reset(adev) || amdgpu_ras_in_recovery(adev)) && - ((smu_funcs && smu_funcs->set_debug_mode) || - (mca_funcs && mca_funcs->mca_set_debug_mode))) + if (amdgpu_in_reset(adev) || amdgpu_ras_in_recovery(adev)) return -EOPNOTSUPP; if (block_obj->hw_ops->reset_ras_error_count) @@ -2090,9 +1986,6 @@ int amdgpu_ras_sysfs_create(struct amdgpu_device *adev, { struct ras_manager *obj = amdgpu_ras_find_obj(adev, head); - if (amdgpu_aca_is_enabled(adev)) - return 0; - if (!obj || obj->attr_inuse) return -EINVAL; @@ -2130,9 +2023,6 @@ int amdgpu_ras_sysfs_remove(struct amdgpu_device *adev, { struct ras_manager *obj = amdgpu_ras_find_obj(adev, head); - if (amdgpu_aca_is_enabled(adev)) - return 0; - if (!obj || !obj->attr_inuse) return -EINVAL; @@ -2245,25 +2135,6 @@ static void amdgpu_ras_debugfs_create(struct amdgpu_device *adev, obj, &amdgpu_ras_debugfs_ops); } -static bool amdgpu_ras_aca_is_supported(struct amdgpu_device *adev) -{ - bool ret; - - switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { - case IP_VERSION(13, 0, 6): - case IP_VERSION(13, 0, 12): - case IP_VERSION(13, 0, 14): - case IP_VERSION(13, 0, 15): - ret = true; - break; - default: - ret = false; - break; - } - - return ret; -} - void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); @@ -2290,13 +2161,6 @@ void amdgpu_ras_debugfs_create_all(struct amdgpu_device *adev) amdgpu_ras_debugfs_create(adev, &fs_info, dir); } } - - if (amdgpu_ras_aca_is_supported(adev)) { - if (amdgpu_aca_is_enabled(adev)) - amdgpu_aca_smu_debugfs_init(adev, dir); - else - amdgpu_mca_smu_debugfs_init(adev, dir); - } } /* debugfs end */ @@ -2489,14 +2353,6 @@ static void amdgpu_ras_interrupt_poison_creation_handler(struct ras_manager *obj event_id = amdgpu_ras_acquire_event_id(adev, type); RAS_EVENT_LOG(adev, event_id, "Poison is created\n"); - if (amdgpu_ip_version(obj->adev, UMC_HWIP, 0) >= IP_VERSION(12, 0, 0)) { - struct amdgpu_ras *con = amdgpu_ras_get_context(obj->adev); - - atomic_inc(&con->page_retirement_req_cnt); - atomic_inc(&con->poison_creation_count); - - wake_up(&con->page_retirement_wq); - } } static void amdgpu_ras_interrupt_umc_handler(struct ras_manager *obj, @@ -3026,77 +2882,6 @@ static int amdgpu_ras_realloc_eh_data_space(struct amdgpu_device *adev, return 0; } -static int amdgpu_ras_mca2pa_by_idx(struct amdgpu_device *adev, - struct eeprom_table_record *bps, - struct ras_err_data *err_data) -{ - struct ta_ras_query_address_input addr_in; - uint32_t socket = 0; - int ret = 0; - - if (adev->smuio.funcs && adev->smuio.funcs->get_socket_id) - socket = adev->smuio.funcs->get_socket_id(adev); - - /* reinit err_data */ - err_data->err_addr_cnt = 0; - err_data->err_addr_len = adev->umc.retire_unit; - - memset(&addr_in, 0, sizeof(addr_in)); - addr_in.ma.err_addr = bps->address; - addr_in.ma.socket_id = socket; - addr_in.ma.ch_inst = bps->mem_channel; - if (!amdgpu_ras_smu_eeprom_supported(adev)) { - /* tell RAS TA the node instance is not used */ - addr_in.ma.node_inst = TA_RAS_INV_NODE; - } else { - addr_in.ma.umc_inst = bps->mcumc_id; - addr_in.ma.node_inst = bps->cu; - } - - if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr) - ret = adev->umc.ras->convert_ras_err_addr(adev, err_data, - &addr_in, NULL, false); - - return ret; -} - -static int amdgpu_ras_mca2pa(struct amdgpu_device *adev, - struct eeprom_table_record *bps, - struct ras_err_data *err_data) -{ - struct ta_ras_query_address_input addr_in; - uint32_t die_id, socket = 0; - - if (adev->smuio.funcs && adev->smuio.funcs->get_socket_id) - socket = adev->smuio.funcs->get_socket_id(adev); - - /* although die id is gotten from PA in nps1 mode, the id is - * fitable for any nps mode - */ - if (adev->umc.ras && adev->umc.ras->get_die_id_from_pa) - die_id = adev->umc.ras->get_die_id_from_pa(adev, bps->address, - bps->retired_page << AMDGPU_GPU_PAGE_SHIFT); - else - return -EINVAL; - - /* reinit err_data */ - err_data->err_addr_cnt = 0; - err_data->err_addr_len = adev->umc.retire_unit; - - memset(&addr_in, 0, sizeof(addr_in)); - addr_in.ma.err_addr = bps->address; - addr_in.ma.ch_inst = bps->mem_channel; - addr_in.ma.umc_inst = bps->mcumc_id; - addr_in.ma.node_inst = die_id; - addr_in.ma.socket_id = socket; - - if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr) - return adev->umc.ras->convert_ras_err_addr(adev, err_data, - &addr_in, NULL, false); - else - return -EINVAL; -} - static bool __check_record_in_range(struct amdgpu_device *adev, struct eeprom_table_record *bps, int count) { @@ -3157,117 +2942,13 @@ static int __amdgpu_ras_convert_rec_array_from_rom(struct amdgpu_device *adev, struct eeprom_table_record *bps, struct ras_err_data *err_data, enum amdgpu_memory_partition nps) { - int i = 0; - uint64_t chan_idx_v2; - enum amdgpu_memory_partition save_nps; - - save_nps = (bps[0].retired_page >> UMC_NPS_SHIFT) & UMC_NPS_MASK; - chan_idx_v2 = bps[0].retired_page & UMC_CHANNEL_IDX_V2; - /*old asics just have pa in eeprom*/ - if (IP_VERSION_MAJ(amdgpu_ip_version(adev, UMC_HWIP, 0)) < 12) { - memcpy(err_data->err_addr, bps, - sizeof(struct eeprom_table_record) * adev->umc.retire_unit); - goto out; - } + memcpy(err_data->err_addr, bps, + sizeof(struct eeprom_table_record) * adev->umc.retire_unit); - for (i = 0; i < adev->umc.retire_unit; i++) - bps[i].retired_page &= ~(UMC_NPS_MASK << UMC_NPS_SHIFT); - - if (save_nps || chan_idx_v2) { - if (save_nps == nps) { - if (amdgpu_umc_pages_in_a_row(adev, err_data, - bps[0].retired_page << AMDGPU_GPU_PAGE_SHIFT)) - return -EINVAL; - for (i = 0; i < adev->umc.retire_unit; i++) { - err_data->err_addr[i].address = bps[0].address; - err_data->err_addr[i].mem_channel = bps[0].mem_channel; - err_data->err_addr[i].bank = bps[0].bank; - err_data->err_addr[i].err_type = bps[0].err_type; - err_data->err_addr[i].mcumc_id = bps[0].mcumc_id; - } - } else { - if (amdgpu_ras_mca2pa_by_idx(adev, &bps[0], err_data)) - return -EINVAL; - } - } else { - if (bps[0].address == 0) { - /* for specific old eeprom data, mca address is not stored, - * calc it from pa - */ - if (amdgpu_umc_pa2mca(adev, bps[0].retired_page << AMDGPU_GPU_PAGE_SHIFT, - &(bps[0].address), AMDGPU_NPS1_PARTITION_MODE)) - return -EINVAL; - } - - if (amdgpu_ras_mca2pa(adev, &bps[0], err_data)) { - if (nps == AMDGPU_NPS1_PARTITION_MODE) - memcpy(err_data->err_addr, bps, - sizeof(struct eeprom_table_record) * adev->umc.retire_unit); - else - return -EOPNOTSUPP; - } - } - -out: return __amdgpu_ras_restore_bad_pages(adev, err_data->err_addr, adev->umc.retire_unit); } -static int __amdgpu_ras_convert_rec_from_rom(struct amdgpu_device *adev, - struct eeprom_table_record *bps, struct ras_err_data *err_data, - enum amdgpu_memory_partition nps) -{ - int i = 0; - uint64_t chan_idx_v2; - enum amdgpu_memory_partition save_nps; - - if (!amdgpu_ras_smu_eeprom_supported(adev)) { - save_nps = (bps->retired_page >> UMC_NPS_SHIFT) & UMC_NPS_MASK; - chan_idx_v2 = bps->retired_page & UMC_CHANNEL_IDX_V2; - bps->retired_page &= ~(UMC_NPS_MASK << UMC_NPS_SHIFT); - } else { - /* if pmfw manages eeprom, save_nps is not stored on eeprom, - * we should always convert mca address into physical address, - * make save_nps different from nps - */ - save_nps = nps + 1; - } - - if (save_nps == nps) { - if (amdgpu_umc_pages_in_a_row(adev, err_data, - bps->retired_page << AMDGPU_GPU_PAGE_SHIFT)) - return -EINVAL; - for (i = 0; i < adev->umc.retire_unit; i++) { - err_data->err_addr[i].address = bps->address; - err_data->err_addr[i].mem_channel = bps->mem_channel; - err_data->err_addr[i].bank = bps->bank; - err_data->err_addr[i].err_type = bps->err_type; - err_data->err_addr[i].mcumc_id = bps->mcumc_id; - } - } else { - if (save_nps || chan_idx_v2) { - if (amdgpu_ras_mca2pa_by_idx(adev, bps, err_data)) - return -EINVAL; - } else { - /* for specific old eeprom data, mca address is not stored, - * calc it from pa - */ - if (bps->address == 0) - if (amdgpu_umc_pa2mca(adev, - bps->retired_page << AMDGPU_GPU_PAGE_SHIFT, - &(bps->address), - AMDGPU_NPS1_PARTITION_MODE)) - return -EINVAL; - - if (amdgpu_ras_mca2pa(adev, bps, err_data)) - return -EOPNOTSUPP; - } - } - - return __amdgpu_ras_restore_bad_pages(adev, err_data->err_addr, - adev->umc.retire_unit); -} - /* it deal with vram only. */ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, struct eeprom_table_record *bps, int pages, bool from_rom) @@ -3300,8 +2981,7 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, if (from_rom) { /* there is no pa recs in V3, so skip pa recs processing */ - if ((control->tbl_hdr.version < RAS_TABLE_VER_V3) && - !amdgpu_ras_smu_eeprom_supported(adev)) { + if (control->tbl_hdr.version < RAS_TABLE_VER_V3) { for (i = 0; i < pages; i++) { if (control->ras_num_recs - i >= adev->umc.retire_unit) { if ((bps[i].address == bps[i + 1].address) && @@ -3318,10 +2998,8 @@ int amdgpu_ras_add_bad_pages(struct amdgpu_device *adev, } } } - for (; i < pages; i++) { - ret = __amdgpu_ras_convert_rec_from_rom(adev, - &bps[i], &err_data, nps); - } + for (; i < pages; i++) + bps[i].retired_page &= ~(UMC_NPS_MASK << UMC_NPS_SHIFT); con->eh_data->count_saved = con->eh_data->count; } else { @@ -3346,7 +3024,7 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev, struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct ras_err_handler_data *data; struct amdgpu_ras_eeprom_control *control; - int save_count, unit_num, i; + int save_count, unit_num; if (!con || !con->eh_data) { if (new_cnt) @@ -3367,12 +3045,7 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev, mutex_lock(&con->recovery_lock); control = &con->eeprom_control; data = con->eh_data; - if (amdgpu_ras_smu_eeprom_supported(adev)) - unit_num = control->ras_num_recs - - control->ras_num_recs_old; - else - unit_num = data->count / adev->umc.retire_unit - - control->ras_num_recs; + unit_num = data->count / adev->umc.retire_unit - control->ras_num_recs; save_count = con->bad_page_num - control->ras_num_bad_pages; mutex_unlock(&con->recovery_lock); @@ -3383,21 +3056,10 @@ int amdgpu_ras_save_bad_pages(struct amdgpu_device *adev, /* only new entries are saved */ if (unit_num && save_count) { /*old asics only save pa to eeprom like before*/ - if (IP_VERSION_MAJ(amdgpu_ip_version(adev, UMC_HWIP, 0)) < 12) { - if (amdgpu_ras_eeprom_append(control, - &data->bps[data->count_saved], unit_num)) { - dev_err(adev->dev, "Failed to save EEPROM table data!"); - return -EIO; - } - } else { - for (i = 0; i < unit_num; i++) { - if (amdgpu_ras_eeprom_append(control, - &data->bps[data->count_saved + - i * adev->umc.retire_unit], 1)) { - dev_err(adev->dev, "Failed to save EEPROM table data!"); - return -EIO; - } - } + if (amdgpu_ras_eeprom_append(control, + &data->bps[data->count_saved], unit_num)) { + dev_err(adev->dev, "Failed to save EEPROM table data!"); + return -EIO; } dev_info(adev->dev, "Saved %d pages to EEPROM table.\n", save_count); @@ -3416,7 +3078,7 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) struct amdgpu_ras_eeprom_control *control = &adev->psp.ras_context.ras->eeprom_control; struct eeprom_table_record *bps; - int ret, i = 0; + int ret; /* no bad page record, skip eeprom access */ if (control->ras_num_recs == 0 || amdgpu_bad_page_threshold == 0) @@ -3430,33 +3092,6 @@ static int amdgpu_ras_load_bad_pages(struct amdgpu_device *adev) if (ret) { dev_err(adev->dev, "Failed to load EEPROM table records!"); } else { - if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr) { - /*In V3, there is no pa recs, and some cases(when address==0) may be parsed - as pa recs, so add verion check to avoid it. - */ - if ((control->tbl_hdr.version < RAS_TABLE_VER_V3) && - !amdgpu_ras_smu_eeprom_supported(adev)) { - for (i = 0; i < control->ras_num_recs; i++) { - if ((control->ras_num_recs - i) >= adev->umc.retire_unit) { - if ((bps[i].address == bps[i + 1].address) && - (bps[i].mem_channel == bps[i + 1].mem_channel)) { - control->ras_num_pa_recs += adev->umc.retire_unit; - i += (adev->umc.retire_unit - 1); - } else { - control->ras_num_mca_recs += - (control->ras_num_recs - i); - break; - } - } else { - control->ras_num_mca_recs += (control->ras_num_recs - i); - break; - } - } - } else { - control->ras_num_mca_recs = control->ras_num_recs; - } - } - ret = amdgpu_ras_add_bad_pages(adev, bps, control->ras_num_recs, true); if (ret) goto out; @@ -3550,293 +3185,6 @@ static void amdgpu_ras_validate_threshold(struct amdgpu_device *adev, } } -int amdgpu_ras_put_poison_req(struct amdgpu_device *adev, - enum amdgpu_ras_block block, uint16_t pasid, - pasid_notify pasid_fn, void *data, uint32_t reset) -{ - int ret = 0; - struct ras_poison_msg poison_msg; - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - - memset(&poison_msg, 0, sizeof(poison_msg)); - poison_msg.block = block; - poison_msg.pasid = pasid; - poison_msg.reset = reset; - poison_msg.pasid_fn = pasid_fn; - poison_msg.data = data; - - ret = kfifo_put(&con->poison_fifo, poison_msg); - if (!ret) { - dev_err(adev->dev, "Poison message fifo is full!\n"); - return -ENOSPC; - } - - return 0; -} - -static int amdgpu_ras_get_poison_req(struct amdgpu_device *adev, - struct ras_poison_msg *poison_msg) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - - return kfifo_get(&con->poison_fifo, poison_msg); -} - -static void amdgpu_ras_ecc_log_init(struct ras_ecc_log_info *ecc_log) -{ - mutex_init(&ecc_log->lock); - - INIT_RADIX_TREE(&ecc_log->de_page_tree, GFP_KERNEL); - ecc_log->de_queried_count = 0; - ecc_log->consumption_q_count = 0; -} - -static void amdgpu_ras_ecc_log_fini(struct ras_ecc_log_info *ecc_log) -{ - struct radix_tree_iter iter; - void __rcu **slot; - struct ras_ecc_err *ecc_err; - - mutex_lock(&ecc_log->lock); - radix_tree_for_each_slot(slot, &ecc_log->de_page_tree, &iter, 0) { - ecc_err = radix_tree_deref_slot(slot); - kfree(ecc_err->err_pages.pfn); - kfree(ecc_err); - radix_tree_iter_delete(&ecc_log->de_page_tree, &iter, slot); - } - mutex_unlock(&ecc_log->lock); - - mutex_destroy(&ecc_log->lock); - ecc_log->de_queried_count = 0; - ecc_log->consumption_q_count = 0; -} - -static bool amdgpu_ras_schedule_retirement_dwork(struct amdgpu_ras *con, - uint32_t delayed_ms) -{ - int ret; - - mutex_lock(&con->umc_ecc_log.lock); - ret = radix_tree_tagged(&con->umc_ecc_log.de_page_tree, - UMC_ECC_NEW_DETECTED_TAG); - mutex_unlock(&con->umc_ecc_log.lock); - - if (ret) - schedule_delayed_work(&con->page_retirement_dwork, - msecs_to_jiffies(delayed_ms)); - - return ret ? true : false; -} - -static void amdgpu_ras_do_page_retirement(struct work_struct *work) -{ - struct amdgpu_ras *con = container_of(work, struct amdgpu_ras, - page_retirement_dwork.work); - struct amdgpu_device *adev = con->adev; - struct ras_err_data err_data; - - /* If gpu reset is ongoing, delay retiring the bad pages */ - if (amdgpu_in_reset(adev) || amdgpu_ras_in_recovery(adev)) { - amdgpu_ras_schedule_retirement_dwork(con, - AMDGPU_RAS_RETIRE_PAGE_INTERVAL * 3); - return; - } - - amdgpu_ras_error_data_init(&err_data); - - amdgpu_umc_handle_bad_pages(adev, &err_data); - - amdgpu_ras_error_data_fini(&err_data); - - amdgpu_ras_schedule_retirement_dwork(con, - AMDGPU_RAS_RETIRE_PAGE_INTERVAL); -} - -static int amdgpu_ras_poison_creation_handler(struct amdgpu_device *adev, - uint32_t poison_creation_count) -{ - int ret = 0; - struct ras_ecc_log_info *ecc_log; - struct ras_query_if info; - u32 timeout = MAX_UMC_POISON_POLLING_TIME_ASYNC; - struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - u64 de_queried_count; - u64 consumption_q_count; - enum ras_event_type type = RAS_EVENT_TYPE_POISON_CREATION; - - memset(&info, 0, sizeof(info)); - info.head.block = AMDGPU_RAS_BLOCK__UMC; - - ecc_log = &ras->umc_ecc_log; - ecc_log->de_queried_count = 0; - ecc_log->consumption_q_count = 0; - - do { - ret = amdgpu_ras_query_error_status_with_event(adev, &info, type); - if (ret) - return ret; - - de_queried_count = ecc_log->de_queried_count; - consumption_q_count = ecc_log->consumption_q_count; - - if (de_queried_count && consumption_q_count) - break; - - msleep(100); - } while (--timeout); - - if (de_queried_count) - schedule_delayed_work(&ras->page_retirement_dwork, 0); - - if (amdgpu_ras_is_rma(adev) && atomic_cmpxchg(&ras->rma_in_recovery, 0, 1) == 0) - amdgpu_ras_reset_gpu(adev); - - return 0; -} - -static void amdgpu_ras_clear_poison_fifo(struct amdgpu_device *adev) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - struct ras_poison_msg msg; - int ret; - - do { - ret = kfifo_get(&con->poison_fifo, &msg); - } while (ret); -} - -static int amdgpu_ras_poison_consumption_handler(struct amdgpu_device *adev, - uint32_t msg_count, uint32_t *gpu_reset) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - uint32_t reset_flags = 0, reset = 0; - struct ras_poison_msg msg; - int ret, i; - - kgd2kfd_set_sram_ecc_flag(adev->kfd.dev); - - for (i = 0; i < msg_count; i++) { - ret = amdgpu_ras_get_poison_req(adev, &msg); - if (!ret) - continue; - - if (msg.pasid_fn) - msg.pasid_fn(adev, msg.pasid, msg.data); - - reset_flags |= msg.reset; - } - - /* - * Try to ensure poison creation handler is completed first - * to set rma if bad page exceed threshold. - */ - flush_delayed_work(&con->page_retirement_dwork); - - /* for RMA, amdgpu_ras_poison_creation_handler will trigger gpu reset */ - if (reset_flags && !amdgpu_ras_is_rma(adev)) { - if (reset_flags & AMDGPU_RAS_GPU_RESET_MODE1_RESET) - reset = AMDGPU_RAS_GPU_RESET_MODE1_RESET; - else if (reset_flags & AMDGPU_RAS_GPU_RESET_MODE2_RESET) - reset = AMDGPU_RAS_GPU_RESET_MODE2_RESET; - else - reset = reset_flags; - - con->gpu_reset_flags |= reset; - amdgpu_ras_reset_gpu(adev); - - *gpu_reset = reset; - - /* Wait for gpu recovery to complete */ - flush_work(&con->recovery_work); - } - - return 0; -} - -static int amdgpu_ras_page_retirement_thread(void *param) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)param; - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - uint32_t poison_creation_count, msg_count; - uint32_t gpu_reset; - int ret; - - while (!kthread_should_stop()) { - - wait_event_interruptible(con->page_retirement_wq, - kthread_should_stop() || - atomic_read(&con->page_retirement_req_cnt)); - - if (kthread_should_stop()) - break; - - mutex_lock(&con->poison_lock); - gpu_reset = 0; - - do { - poison_creation_count = atomic_read(&con->poison_creation_count); - ret = amdgpu_ras_poison_creation_handler(adev, poison_creation_count); - if (ret == -EIO) - break; - - if (poison_creation_count) { - atomic_sub(poison_creation_count, &con->poison_creation_count); - atomic_sub(poison_creation_count, &con->page_retirement_req_cnt); - } - } while (atomic_read(&con->poison_creation_count) && - !atomic_read(&con->poison_consumption_count)); - - if (ret != -EIO) { - msg_count = kfifo_len(&con->poison_fifo); - if (msg_count) { - ret = amdgpu_ras_poison_consumption_handler(adev, - msg_count, &gpu_reset); - if ((ret != -EIO) && - (gpu_reset != AMDGPU_RAS_GPU_RESET_MODE1_RESET)) - atomic_sub(msg_count, &con->page_retirement_req_cnt); - } - } - - if ((ret == -EIO) || (gpu_reset == AMDGPU_RAS_GPU_RESET_MODE1_RESET)) { - /* gpu mode-1 reset is ongoing or just completed ras mode-1 reset */ - /* Clear poison creation request */ - atomic_set(&con->poison_creation_count, 0); - atomic_set(&con->poison_consumption_count, 0); - - /* Clear poison fifo */ - amdgpu_ras_clear_poison_fifo(adev); - - /* Clear all poison requests */ - atomic_set(&con->page_retirement_req_cnt, 0); - - if (ret == -EIO) { - /* Wait for mode-1 reset to complete */ - down_read(&adev->reset_domain->sem); - up_read(&adev->reset_domain->sem); - } - - /* Wake up work to save bad pages to eeprom */ - schedule_delayed_work(&con->page_retirement_dwork, 0); - } else if (gpu_reset) { - /* gpu just completed mode-2 reset or other reset */ - /* Clear poison consumption messages cached in fifo */ - msg_count = kfifo_len(&con->poison_fifo); - if (msg_count) { - amdgpu_ras_clear_poison_fifo(adev); - atomic_sub(msg_count, &con->page_retirement_req_cnt); - } - - atomic_set(&con->poison_consumption_count, 0); - - /* Wake up work to save bad pages to eeprom */ - schedule_delayed_work(&con->page_retirement_dwork, 0); - } - mutex_unlock(&con->poison_lock); - } - - return 0; -} - int amdgpu_ras_init_badpage_info(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); @@ -3846,7 +3194,14 @@ int amdgpu_ras_init_badpage_info(struct amdgpu_device *adev) if (!con || amdgpu_sriov_vf(adev)) return 0; - if (amdgpu_uniras_enabled(adev)) + /* + * For the reset-on-init path (e.g. an NPS memory partition, + * switch) the RAS IP block hw_init has not been enabled and + * the amdgpu_uniras_enabled return false, check amdgpu ras + * context uniras_enabled flag, eeprom init will be called + * during RAS IP block hw_init. + */ + if (amdgpu_uniras_enabled(adev) || con->uniras_enabled) return 0; control = &con->eeprom_control; @@ -3855,9 +3210,6 @@ int amdgpu_ras_init_badpage_info(struct amdgpu_device *adev) ret = amdgpu_ras_eeprom_init(control); control->is_eeprom_valid = !ret; - if (!adev->umc.ras || !adev->umc.ras->convert_ras_err_addr) - control->ras_num_pa_recs = control->ras_num_recs; - if (adev->umc.ras && adev->umc.ras->get_retire_flip_bits) adev->umc.ras->get_retire_flip_bits(adev); @@ -3877,13 +3229,6 @@ int amdgpu_ras_init_badpage_info(struct amdgpu_device *adev) adev, control->bad_channel_bitmap); con->update_channel_flag = false; } - - /* The format action is only applied to new ASICs */ - if (IP_VERSION_MAJ(amdgpu_ip_version(adev, UMC_HWIP, 0)) >= 12 && - control->tbl_hdr.version < RAS_TABLE_VER_V3) - if (!amdgpu_ras_eeprom_reset_table(control)) - if (amdgpu_ras_save_bad_pages(adev, NULL)) - dev_warn(adev->dev, "Failed to format RAS EEPROM data in V3 version!\n"); } return 0; @@ -3917,10 +3262,8 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev, bool init_bp_info) } mutex_init(&con->recovery_lock); - mutex_init(&con->poison_lock); INIT_WORK(&con->recovery_work, amdgpu_ras_do_recovery); atomic_set(&con->in_recovery, 0); - atomic_set(&con->rma_in_recovery, 0); con->eeprom_control.bad_channel_bitmap = 0; max_eeprom_records_count = amdgpu_ras_eeprom_max_record_count(&con->eeprom_control); @@ -3933,21 +3276,8 @@ int amdgpu_ras_recovery_init(struct amdgpu_device *adev, bool init_bp_info) } mutex_init(&con->page_rsv_lock); - INIT_KFIFO(con->poison_fifo); mutex_init(&con->page_retirement_lock); - init_waitqueue_head(&con->page_retirement_wq); - atomic_set(&con->page_retirement_req_cnt, 0); - atomic_set(&con->poison_creation_count, 0); - atomic_set(&con->poison_consumption_count, 0); - con->page_retirement_thread = - kthread_run(amdgpu_ras_page_retirement_thread, adev, "umc_page_retirement"); - if (IS_ERR(con->page_retirement_thread)) { - con->page_retirement_thread = NULL; - dev_warn(adev->dev, "Failed to create umc_page_retirement thread!!!\n"); - } - INIT_DELAYED_WORK(&con->page_retirement_dwork, amdgpu_ras_do_page_retirement); - amdgpu_ras_ecc_log_init(&con->umc_ecc_log); #ifdef CONFIG_X86_MCE_AMD if ((adev->asic_type == CHIP_ALDEBARAN) && (adev->gmc.xgmi.connected_to_cpu)) @@ -3978,33 +3308,15 @@ static int amdgpu_ras_recovery_fini(struct amdgpu_device *adev) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); struct ras_err_handler_data *data = con->eh_data; - int max_flush_timeout = MAX_FLUSH_RETIRE_DWORK_TIMES; - bool ret; /* recovery_init failed to init it, fini is useless */ if (!data) return 0; - /* Save all cached bad pages to eeprom */ - do { - flush_delayed_work(&con->page_retirement_dwork); - ret = amdgpu_ras_schedule_retirement_dwork(con, 0); - } while (ret && max_flush_timeout--); - - if (con->page_retirement_thread) - kthread_stop(con->page_retirement_thread); - - atomic_set(&con->page_retirement_req_cnt, 0); - atomic_set(&con->poison_creation_count, 0); - mutex_destroy(&con->page_rsv_lock); cancel_work_sync(&con->recovery_work); - cancel_delayed_work_sync(&con->page_retirement_dwork); - - amdgpu_ras_ecc_log_fini(&con->umc_ecc_log); - mutex_lock(&con->recovery_lock); con->eh_data = NULL; kfree(data->bps); @@ -4206,15 +3518,6 @@ static void amdgpu_ras_check_supported(struct amdgpu_device *adev) adev->ras_enabled = amdgpu_ras_enable == 0 ? 0 : adev->ras_hw_enabled & amdgpu_ras_mask; - /* aca is disabled by default except for psp v13_0_6/v13_0_12/v13_0_14 */ - if (!amdgpu_sriov_vf(adev)) { - adev->aca.is_enabled = - (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6) || - amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 12) || - amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) || - amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 15)); - } - /* bad page feature is not applicable to specific app platform */ if (adev->gmc.is_app_apu && amdgpu_ip_version(adev, UMC_HWIP, 0) == IP_VERSION(12, 0, 0)) @@ -4435,15 +3738,6 @@ int amdgpu_ras_init(struct amdgpu_device *adev) goto release_con; } - if (amdgpu_ras_aca_is_supported(adev)) { - if (amdgpu_aca_is_enabled(adev)) - r = amdgpu_aca_init(adev); - else - r = amdgpu_mca_init(adev); - if (r) - goto release_con; - } - con->init_task_pid = task_pid_nr(current); get_task_comm(con->init_task_comm, current); @@ -4541,9 +3835,9 @@ int amdgpu_ras_block_late_init(struct amdgpu_device *adev, goto cleanup; } - if (ras_obj->hw_ops && + if (amdgpu_uniras_enabled(adev) || (ras_obj->hw_ops && (ras_obj->hw_ops->query_ras_error_count || - ras_obj->hw_ops->query_ras_error_status)) { + ras_obj->hw_ops->query_ras_error_status))) { r = amdgpu_ras_sysfs_create(adev, ras_block); if (r) goto interrupt; @@ -4671,28 +3965,13 @@ int amdgpu_ras_late_init(struct amdgpu_device *adev) amdgpu_ras_event_mgr_init(adev); - if (amdgpu_ras_aca_is_supported(adev)) { - if (amdgpu_reset_in_recovery(adev)) { - if (amdgpu_aca_is_enabled(adev)) - r = amdgpu_aca_reset(adev); - else - r = amdgpu_mca_reset(adev); - if (r) - return r; - } - - if (!amdgpu_sriov_vf(adev)) { - if (amdgpu_aca_is_enabled(adev)) - amdgpu_ras_set_aca_debug_mode(adev, false); - else - amdgpu_ras_set_mca_debug_mode(adev, false); - } - } - /* Guest side doesn't need init ras feature */ if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_ras_telemetry_en(adev)) return 0; + if (amdgpu_uniras_enabled(adev)) + amdgpu_ras_mgr_set_debug_mode(adev, false); + list_for_each_entry_safe(node, tmp, &adev->ras_list, node) { obj = node->ras_obj; if (!obj) { @@ -4773,13 +4052,6 @@ int amdgpu_ras_fini(struct amdgpu_device *adev) amdgpu_ras_fs_fini(adev); amdgpu_ras_interrupt_remove_all(adev); - if (amdgpu_ras_aca_is_supported(adev)) { - if (amdgpu_aca_is_enabled(adev)) - amdgpu_aca_fini(adev); - else - amdgpu_mca_fini(adev); - } - WARN(AMDGPU_RAS_GET_FEATURES(con->features), "Feature mask is not cleared"); if (AMDGPU_RAS_GET_FEATURES(con->features)) @@ -5064,6 +4336,13 @@ static void amdgpu_register_bad_pages_mca_notifier(struct amdgpu_device *adev) * Use this list instead of mgpu_info to find the amdgpu * device on which the UMC error was reported. */ + if (mce_adev_list.num_gpu >= MAX_GPU_INSTANCE) { + dev_warn_ratelimited(adev->dev, + "mce_adev_list full, skip notifier registration (max=%d)\n", + MAX_GPU_INSTANCE); + return; + } + mce_adev_list.devs[mce_adev_list.num_gpu++] = adev; /* @@ -5181,59 +4460,10 @@ int amdgpu_ras_reset_gpu(struct amdgpu_device *adev) return 0; } -int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - int ret = 0; - - if (con) { - ret = amdgpu_mca_smu_set_debug_mode(adev, enable); - if (!ret) - con->is_aca_debug_mode = enable; - } - - return ret; -} - -int amdgpu_ras_set_aca_debug_mode(struct amdgpu_device *adev, bool enable) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - int ret = 0; - - if (con) { - if (amdgpu_aca_is_enabled(adev)) - ret = amdgpu_aca_smu_set_debug_mode(adev, enable); - else - ret = amdgpu_mca_smu_set_debug_mode(adev, enable); - if (!ret) - con->is_aca_debug_mode = enable; - } - - return ret; -} - -bool amdgpu_ras_get_aca_debug_mode(struct amdgpu_device *adev) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - const struct aca_smu_funcs *smu_funcs = adev->aca.smu_funcs; - const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; - - if (!con) - return false; - - if ((amdgpu_aca_is_enabled(adev) && smu_funcs && smu_funcs->set_debug_mode) || - (!amdgpu_aca_is_enabled(adev) && mca_funcs && mca_funcs->mca_set_debug_mode)) - return con->is_aca_debug_mode; - else - return true; -} - bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, unsigned int *error_query_mode) { struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - const struct amdgpu_mca_smu_funcs *mca_funcs = adev->mca.mca_funcs; - const struct aca_smu_funcs *smu_funcs = adev->aca.smu_funcs; if (!con) { *error_query_mode = AMDGPU_RAS_INVALID_ERROR_QUERY; @@ -5242,9 +4472,6 @@ bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, if (amdgpu_sriov_vf(adev)) { *error_query_mode = AMDGPU_RAS_VIRT_ERROR_COUNT_QUERY; - } else if ((smu_funcs && smu_funcs->set_debug_mode) || (mca_funcs && mca_funcs->mca_set_debug_mode)) { - *error_query_mode = - (con->is_aca_debug_mode) ? AMDGPU_RAS_DIRECT_ERROR_QUERY : AMDGPU_RAS_FIRMWARE_ERROR_QUERY; } else { *error_query_mode = AMDGPU_RAS_DIRECT_ERROR_QUERY; } @@ -5834,3 +5061,8 @@ void amdgpu_ras_post_reset(struct amdgpu_device *adev, amdgpu_ras_mgr_post_reset(tmp_adev); } } + +void amdgpu_ras_resume_after_reset(struct amdgpu_device *adev) +{ + amdgpu_ras_mgr_resume_after_reset(adev); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h index a86ab65aa2f0..a44aed7f169e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.h @@ -31,7 +31,6 @@ #include "ta_ras_if.h" #include "amdgpu_ras_eeprom.h" #include "amdgpu_smuio.h" -#include "amdgpu_aca.h" struct amdgpu_iv_entry; @@ -466,14 +465,6 @@ struct ras_query_context { typedef int (*pasid_notify)(struct amdgpu_device *adev, uint16_t pasid, void *data); -struct ras_poison_msg { - enum amdgpu_ras_block block; - uint16_t pasid; - uint32_t reset; - pasid_notify pasid_fn; - void *data; -}; - struct ras_err_pages { uint32_t count; uint64_t *pfn; @@ -492,8 +483,6 @@ struct ras_ecc_err { struct ras_ecc_log_info { struct mutex lock; struct radix_tree_root de_page_tree; - uint64_t de_queried_count; - uint64_t consumption_q_count; }; struct ras_critical_region { @@ -549,7 +538,6 @@ struct amdgpu_ras { /* gpu recovery */ struct work_struct recovery_work; atomic_t in_recovery; - atomic_t rma_in_recovery; struct amdgpu_device *adev; /* error handler data */ struct ras_err_handler_data *eh_data; @@ -581,22 +569,15 @@ struct amdgpu_ras { /* Indicates smu whether need update bad channel info */ bool update_channel_flag; /* Record status of smu mca debug mode */ - bool is_aca_debug_mode; + bool is_mca_debug_mode; bool is_rma; /* Record special requirements of gpu reset caller */ uint32_t gpu_reset_flags; - struct task_struct *page_retirement_thread; - wait_queue_head_t page_retirement_wq; struct mutex page_retirement_lock; - atomic_t page_retirement_req_cnt; - atomic_t poison_creation_count; - atomic_t poison_consumption_count; struct mutex page_rsv_lock; - DECLARE_KFIFO(poison_fifo, struct ras_poison_msg, 128); struct ras_ecc_log_info umc_ecc_log; - struct delayed_work page_retirement_dwork; /* ras errors detected */ unsigned long ras_err_state; @@ -615,9 +596,6 @@ struct amdgpu_ras { struct list_head critical_region_head; struct mutex critical_region_lock; - /* Protect poison injection */ - struct mutex poison_lock; - /* Disable/Enable uniras switch */ bool uniras_enabled; const struct ras_smu_drv *ras_smu_drv; @@ -702,8 +680,6 @@ struct ras_manager { struct ras_ih_data ih_data; struct ras_err_data err_data; - - struct aca_handle aca_handle; }; struct ras_badpage { @@ -964,8 +940,7 @@ struct amdgpu_ras* amdgpu_ras_get_context(struct amdgpu_device *adev); int amdgpu_ras_set_context(struct amdgpu_device *adev, struct amdgpu_ras *ras_con); int amdgpu_ras_set_mca_debug_mode(struct amdgpu_device *adev, bool enable); -int amdgpu_ras_set_aca_debug_mode(struct amdgpu_device *adev, bool enable); -bool amdgpu_ras_get_aca_debug_mode(struct amdgpu_device *adev); +bool amdgpu_ras_get_mca_debug_mode(struct amdgpu_device *adev); bool amdgpu_ras_get_error_query_mode(struct amdgpu_device *adev, unsigned int *mode); @@ -1006,12 +981,6 @@ int amdgpu_ras_error_statistic_de_count(struct ras_err_data *err_data, struct amdgpu_smuio_mcm_config_info *mcm_info, u64 count); void amdgpu_ras_query_boot_status(struct amdgpu_device *adev, u32 num_instances); -int amdgpu_ras_bind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk, - const struct aca_info *aca_info, void *data); -int amdgpu_ras_unbind_aca(struct amdgpu_device *adev, enum amdgpu_ras_block blk); - -ssize_t amdgpu_ras_aca_sysfs_read(struct device *dev, struct device_attribute *attr, - struct aca_handle *handle, char *buf, void *data); void amdgpu_ras_set_fed(struct amdgpu_device *adev, bool status); bool amdgpu_ras_get_fed_status(struct amdgpu_device *adev); @@ -1029,10 +998,6 @@ int amdgpu_ras_reserve_page(struct amdgpu_device *adev, uint64_t pfn); int amdgpu_ras_add_critical_region(struct amdgpu_device *adev, struct amdgpu_bo *bo); bool amdgpu_ras_check_critical_address(struct amdgpu_device *adev, uint64_t addr); -int amdgpu_ras_put_poison_req(struct amdgpu_device *adev, - enum amdgpu_ras_block block, uint16_t pasid, - pasid_notify pasid_fn, void *data, uint32_t reset); - bool amdgpu_ras_in_recovery(struct amdgpu_device *adev); __printf(3, 4) @@ -1045,4 +1010,5 @@ void amdgpu_ras_pre_reset(struct amdgpu_device *adev, struct list_head *device_list); void amdgpu_ras_post_reset(struct amdgpu_device *adev, struct list_head *device_list); +void amdgpu_ras_resume_after_reset(struct amdgpu_device *adev); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c index b265b4d9053f..baa8cc3646d5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c @@ -124,8 +124,6 @@ RAS_TABLE_V2_1_INFO_SIZE) \ / RAS_TABLE_RECORD_SIZE) -#define RAS_SMU_MESSAGE_TIMEOUT_MS 1000 /* 1s */ - /* Given a zero-based index of an EEPROM RAS record, yields the EEPROM * offset off of RAS_TABLE_START. That is, this is something you can * add to control->i2c_address, and then tell I2C layer to read @@ -159,6 +157,9 @@ static bool __is_ras_eeprom_supported(struct amdgpu_device *adev) { + if (amdgpu_sriov_vf(adev)) + return false; + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { case IP_VERSION(11, 0, 2): /* VEGA20 and ARCTURUS */ case IP_VERSION(11, 0, 7): /* Sienna cichlid */ @@ -449,57 +450,46 @@ int amdgpu_ras_eeprom_reset_table(struct amdgpu_ras_eeprom_control *control) struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr; struct amdgpu_ras_eeprom_table_ras_info *rai = &control->tbl_rai; struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - u32 erase_res = 0; u8 csum; int res; mutex_lock(&control->ras_tbl_mutex); - if (!amdgpu_ras_smu_eeprom_supported(adev)) { - hdr->header = RAS_TABLE_HDR_VAL; - amdgpu_ras_set_eeprom_table_version(control); + hdr->header = RAS_TABLE_HDR_VAL; + amdgpu_ras_set_eeprom_table_version(control); - if (hdr->version >= RAS_TABLE_VER_V2_1) { - hdr->first_rec_offset = RAS_RECORD_START_V2_1; - hdr->tbl_size = RAS_TABLE_HEADER_SIZE + - RAS_TABLE_V2_1_INFO_SIZE; - rai->rma_status = GPU_HEALTH_USABLE; + if (hdr->version >= RAS_TABLE_VER_V2_1) { + hdr->first_rec_offset = RAS_RECORD_START_V2_1; + hdr->tbl_size = RAS_TABLE_HEADER_SIZE + + RAS_TABLE_V2_1_INFO_SIZE; + rai->rma_status = GPU_HEALTH_USABLE; - control->ras_record_offset = RAS_RECORD_START_V2_1; - control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1; - /** - * GPU health represented as a percentage. - * 0 means worst health, 100 means fully health. - */ - rai->health_percent = 100; - /* ecc_page_threshold = 0 means disable bad page retirement */ - rai->ecc_page_threshold = con->bad_page_cnt_threshold; - } else { - hdr->first_rec_offset = RAS_RECORD_START; - hdr->tbl_size = RAS_TABLE_HEADER_SIZE; - - control->ras_record_offset = RAS_RECORD_START; - control->ras_max_record_count = RAS_MAX_RECORD_COUNT; - } - - csum = __calc_hdr_byte_sum(control); - if (hdr->version >= RAS_TABLE_VER_V2_1) - csum += __calc_ras_info_byte_sum(control); - csum = -csum; - hdr->checksum = csum; - res = __write_table_header(control); - if (!res && hdr->version > RAS_TABLE_VER_V1) - res = __write_table_ras_info(control); + control->ras_record_offset = RAS_RECORD_START_V2_1; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1; + /** + * GPU health represented as a percentage. + * 0 means worst health, 100 means fully health. + */ + rai->health_percent = 100; + /* ecc_page_threshold = 0 means disable bad page retirement */ + rai->ecc_page_threshold = con->bad_page_cnt_threshold; } else { - res = amdgpu_ras_smu_erase_ras_table(adev, &erase_res); - if (res || erase_res) { - dev_warn(adev->dev, "RAS EEPROM reset failed, res:%d result:%d", - res, erase_res); - if (!res) - res = -EIO; - } + hdr->first_rec_offset = RAS_RECORD_START; + hdr->tbl_size = RAS_TABLE_HEADER_SIZE; + + control->ras_record_offset = RAS_RECORD_START; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT; } + csum = __calc_hdr_byte_sum(control); + if (hdr->version >= RAS_TABLE_VER_V2_1) + csum += __calc_ras_info_byte_sum(control); + csum = -csum; + hdr->checksum = csum; + res = __write_table_header(control); + if (!res && hdr->version > RAS_TABLE_VER_V1) + res = __write_table_ras_info(control); + control->ras_num_recs = 0; control->ras_num_bad_pages = 0; control->ras_num_mca_recs = 0; @@ -662,7 +652,6 @@ amdgpu_ras_eeprom_append_table(struct amdgpu_ras_eeprom_control *control, const u32 num) { struct amdgpu_ras *con = amdgpu_ras_get_context(to_amdgpu_device(control)); - struct amdgpu_device *adev = to_amdgpu_device(control); u32 a, b, i; u8 *buf, *pp; int res; @@ -767,10 +756,7 @@ amdgpu_ras_eeprom_append_table(struct amdgpu_ras_eeprom_control *control, % control->ras_max_record_count; /*old asics only save pa to eeprom like before*/ - if (IP_VERSION_MAJ(amdgpu_ip_version(adev, UMC_HWIP, 0)) < 12) - control->ras_num_pa_recs += num; - else - control->ras_num_mca_recs += num; + control->ras_num_pa_recs += num; control->ras_num_bad_pages = con->bad_page_num; Out: @@ -879,71 +865,6 @@ amdgpu_ras_eeprom_update_header(struct amdgpu_ras_eeprom_control *control) return res; } -int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control) -{ - struct amdgpu_device *adev = to_amdgpu_device(control); - int ret, retry = 20; - - if (!amdgpu_ras_smu_eeprom_supported(adev)) - return 0; - - control->ras_num_recs_old = control->ras_num_recs; - - do { - /* 1000ms timeout is long enough, smu_get_badpage_count won't - * return -EBUSY before timeout. - */ - ret = amdgpu_ras_smu_get_badpage_count(adev, - &(control->ras_num_recs), RAS_SMU_MESSAGE_TIMEOUT_MS); - if (!ret && - (control->ras_num_recs_old == control->ras_num_recs)) { - /* record number update in PMFW needs some time, - * smu_get_badpage_count may return immediately without - * count update, sleep for a while and retry again. - */ - msleep(50); - retry--; - } else { - break; - } - } while (retry); - - /* no update of record number is not a real failure, - * don't print warning here - */ - if (!ret && (control->ras_num_recs_old == control->ras_num_recs)) - ret = -EINVAL; - - return ret; -} - -static int amdgpu_ras_smu_eeprom_append(struct amdgpu_ras_eeprom_control *control) -{ - struct amdgpu_device *adev = to_amdgpu_device(control); - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - - if (!amdgpu_ras_smu_eeprom_supported(adev) || !con) - return 0; - - control->ras_num_bad_pages = con->bad_page_num; - - if (amdgpu_bad_page_threshold != 0 && - control->ras_num_bad_pages > con->bad_page_cnt_threshold) { - dev_warn(adev->dev, - "Saved bad pages %d reaches threshold value %d\n", - control->ras_num_bad_pages, con->bad_page_cnt_threshold); - - if (adev->cper.enabled && amdgpu_cper_generate_bp_threshold_record(adev)) - dev_warn(adev->dev, "fail to generate bad page threshold cper records\n"); - - if ((amdgpu_bad_page_threshold != -1) && - (amdgpu_bad_page_threshold != -2)) - con->is_rma = true; - } - - return 0; -} - /** * amdgpu_ras_eeprom_append -- append records to the EEPROM RAS table * @control: pointer to control structure @@ -968,9 +889,6 @@ int amdgpu_ras_eeprom_append(struct amdgpu_ras_eeprom_control *control, if (!__is_ras_eeprom_supported(adev)) return 0; - if (amdgpu_ras_smu_eeprom_supported(adev)) - return amdgpu_ras_smu_eeprom_append(control); - if (num == 0) { dev_err(adev->dev, "will not append 0 records\n"); return -EINVAL; @@ -1046,52 +964,6 @@ static int __amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control, return res; } -int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control, - struct eeprom_table_record *record, u32 rec_idx, - const u32 num) -{ - struct amdgpu_device *adev = to_amdgpu_device(control); - uint64_t ts, end_idx; - int i, ret; - u64 mca, ipid; - u32 cu, mem_channel, mcumc_id; - - if (!amdgpu_ras_smu_eeprom_supported(adev)) - return 0; - - if (!adev->umc.ras || !adev->umc.ras->mca_ipid_parse) - return -EOPNOTSUPP; - - end_idx = rec_idx + num; - for (i = rec_idx; i < end_idx; i++) { - ret = amdgpu_ras_smu_get_badpage_mca_addr(adev, i, &mca); - if (ret) - return ret; - - ret = amdgpu_ras_smu_get_badpage_ipid(adev, i, &ipid); - if (ret) - return ret; - - ret = amdgpu_ras_smu_get_timestamp(adev, i, &ts); - if (ret) - return ret; - - record[i - rec_idx].address = mca; - /* retired_page (pa) is unused now */ - record[i - rec_idx].retired_page = 0x1ULL; - record[i - rec_idx].ts = ts; - record[i - rec_idx].err_type = AMDGPU_RAS_EEPROM_ERR_NON_RECOVERABLE; - - adev->umc.ras->mca_ipid_parse(adev, ipid, - &cu, &mem_channel, &mcumc_id, NULL); - record[i - rec_idx].cu = (u8)cu; - record[i - rec_idx].mem_channel = (u8)mem_channel; - record[i - rec_idx].mcumc_id = (u8)mcumc_id; - } - - return 0; -} - /** * amdgpu_ras_eeprom_read -- read EEPROM * @control: pointer to control structure @@ -1113,9 +985,6 @@ int amdgpu_ras_eeprom_read(struct amdgpu_ras_eeprom_control *control, u8 *buf, *pp; u32 g0, g1; - if (amdgpu_ras_smu_eeprom_supported(adev)) - return amdgpu_ras_eeprom_read_idx(control, record, 0, num); - if (!__is_ras_eeprom_supported(adev)) return 0; @@ -1395,6 +1264,86 @@ static ssize_t amdgpu_ras_debugfs_table_read(struct file *f, char __user *buf, return res < 0 ? res : orig_size - size; } +static ssize_t +amdgpu_ras_debugfs_table_read_uniras(struct amdgpu_device *adev, + char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev); + struct ras_core_context *ras_core = ras_mgr ? ras_mgr->ras_core : NULL; + struct eeprom_umc_record *records = NULL; + struct ras_eeprom_control *control; + size_t bufsz, len = 0; + u32 num_recs; + char *kbuf; + ssize_t res; + int i; + + if (!ras_core) + return 0; + + /* pmfw manages eeprom data by itself */ + if (ras_fw_eeprom_supported(ras_core)) + return 0; + + control = &ras_core->ras_eeprom; + num_recs = ras_eeprom_get_record_count(ras_core); + + bufsz = strlen(tbl_hdr_str) + tbl_hdr_fmt_size + + strlen(rec_hdr_str) + (size_t)rec_hdr_fmt_size * num_recs + 1; + + kbuf = kvmalloc(bufsz, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + if (num_recs) { + records = kvcalloc(num_recs, sizeof(*records), GFP_KERNEL); + if (!records) { + res = -ENOMEM; + goto out; + } + + res = ras_eeprom_read(ras_core, records, num_recs); + if (res) + goto out; + } + + len += scnprintf(kbuf + len, bufsz - len, "%s", tbl_hdr_str); + len += scnprintf(kbuf + len, bufsz - len, tbl_hdr_fmt, + control->tbl_hdr.header, + control->tbl_hdr.version, + control->tbl_hdr.first_rec_offset, + control->tbl_hdr.tbl_size, + control->tbl_hdr.checksum); + len += scnprintf(kbuf + len, bufsz - len, "%s", rec_hdr_str); + + for (i = 0; i < num_recs; i++) { + u32 ai = RAS_RI_TO_AI(control, i); + int et = records[i].err_type; + const char *ets = (et >= 0 && et < AMDGPU_RAS_EEPROM_ERR_COUNT) ? + record_err_type_str[et] : "na"; + + len += scnprintf(kbuf + len, bufsz - len, rec_hdr_fmt, + i, + RAS_INDEX_TO_OFFSET(control, ai), + ets, + records[i].bank, + records[i].ts, + records[i].offset, + records[i].mem_channel, + records[i].mcumc_id, + records[i].retired_row_pfn); + } + + res = simple_read_from_buffer(buf, size, pos, kbuf, len); + +out: + kvfree(records); + kvfree(kbuf); + + return res; +} + static ssize_t amdgpu_ras_debugfs_eeprom_table_read(struct file *f, char __user *buf, size_t size, loff_t *pos) @@ -1408,6 +1357,10 @@ amdgpu_ras_debugfs_eeprom_table_read(struct file *f, char __user *buf, if (!size) return size; + if (amdgpu_uniras_enabled(adev)) + return amdgpu_ras_debugfs_table_read_uniras(adev, buf, + size, pos); + if (!ras || !control) { res = snprintf(data, sizeof(data), "Not supported\n"); if (*pos >= res) @@ -1521,42 +1474,6 @@ static int __read_table_ras_info(struct amdgpu_ras_eeprom_control *control) return res == RAS_TABLE_V2_1_INFO_SIZE ? 0 : res; } -static int amdgpu_ras_smu_eeprom_init(struct amdgpu_ras_eeprom_control *control) -{ - struct amdgpu_device *adev = to_amdgpu_device(control); - struct amdgpu_ras_eeprom_table_header *hdr = &control->tbl_hdr; - struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - uint64_t local_time; - int res; - - ras->is_rma = false; - - if (!__is_ras_eeprom_supported(adev)) - return 0; - mutex_init(&control->ras_tbl_mutex); - - res = amdgpu_ras_smu_get_table_version(adev, &(hdr->version)); - if (res) - return res; - - res = amdgpu_ras_smu_get_badpage_count(adev, - &(control->ras_num_recs), 100); - if (res) - return res; - - local_time = (uint64_t)ktime_get_real_seconds(); - res = amdgpu_ras_smu_set_timestamp(adev, local_time); - if (res) - return res; - - control->ras_max_record_count = 4000; - - control->ras_num_mca_recs = 0; - control->ras_num_pa_recs = 0; - - return 0; -} - int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -1567,9 +1484,6 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) uint32_t vram_type = adev->gmc.vram_type; int res; - if (amdgpu_ras_smu_eeprom_supported(adev)) - return amdgpu_ras_smu_eeprom_init(control); - ras->is_rma = false; if (!__is_ras_eeprom_supported(adev)) @@ -1663,47 +1577,6 @@ int amdgpu_ras_eeprom_init(struct amdgpu_ras_eeprom_control *control) return 0; } -static int amdgpu_ras_smu_eeprom_check(struct amdgpu_ras_eeprom_control *control) -{ - struct amdgpu_device *adev = to_amdgpu_device(control); - struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); - - if (!__is_ras_eeprom_supported(adev)) - return 0; - - control->ras_num_bad_pages = ras->bad_page_num; - - if ((ras->bad_page_cnt_threshold < control->ras_num_bad_pages) && - amdgpu_bad_page_threshold != 0) { - dev_warn(adev->dev, - "RAS records:%d exceed threshold:%d\n", - control->ras_num_bad_pages, ras->bad_page_cnt_threshold); - if ((amdgpu_bad_page_threshold == -1) || - (amdgpu_bad_page_threshold == -2)) { - dev_warn(adev->dev, - "Please consult AMD Service Action Guide (SAG) for appropriate service procedures\n"); - } else { - ras->is_rma = true; - dev_warn(adev->dev, - "User defined threshold is set, runtime service will be halt when threshold is reached\n"); - } - - return 0; - } - - dev_dbg(adev->dev, - "Found existing EEPROM table with %d records", - control->ras_num_bad_pages); - - /* Warn if we are at 90% of the threshold or above - */ - if (10 * control->ras_num_bad_pages >= 9 * ras->bad_page_cnt_threshold) - dev_warn(adev->dev, "RAS records:%u exceeds 90%% of threshold:%d", - control->ras_num_bad_pages, - ras->bad_page_cnt_threshold); - return 0; -} - int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control) { struct amdgpu_device *adev = to_amdgpu_device(control); @@ -1711,9 +1584,6 @@ int amdgpu_ras_eeprom_check(struct amdgpu_ras_eeprom_control *control) struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); int res = 0; - if (amdgpu_ras_smu_eeprom_supported(adev)) - return amdgpu_ras_smu_eeprom_check(control); - if (!__is_ras_eeprom_supported(adev)) return 0; @@ -1973,7 +1843,7 @@ void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev) struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); struct amdgpu_ras_eeprom_control *control = ras ? &ras->eeprom_control : NULL; - if (!control || amdgpu_bad_page_threshold == 0) + if (!__is_ras_eeprom_supported(adev) || !control || amdgpu_bad_page_threshold == 0) return; if (control->ras_num_bad_pages > ras->bad_page_cnt_threshold) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h index a62114800a92..3c7fcce5fe8b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.h @@ -82,7 +82,6 @@ struct amdgpu_ras_eeprom_control { /* Number of records in the table. */ u32 ras_num_recs; - u32 ras_num_recs_old; /* the bad page number is ras_num_recs or * ras_num_recs * umc.retire_unit @@ -191,8 +190,6 @@ int amdgpu_ras_eeprom_read_idx(struct amdgpu_ras_eeprom_control *control, struct eeprom_table_record *record, u32 rec_idx, const u32 num); -int amdgpu_ras_eeprom_update_record_num(struct amdgpu_ras_eeprom_control *control); - void amdgpu_ras_check_bad_page_status(struct amdgpu_device *adev); extern const struct file_operations amdgpu_ras_debugfs_eeprom_size_ops; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index b97fa35bac23..4d417c4a5cd2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -935,6 +935,194 @@ int amdgpu_ring_reset_helper_end(struct amdgpu_ring *ring, return 0; } +/** + * amdgpu_multi_ring_reset_helper_begin() - Prepare multiple rings for a reset. + * + * @ring_type_mask: Bitmask of affected ring types + * @guilty_ring: The ring which is guilty of causing a reset. + * @guilty_fence: The fence which didn't signal on the guilty ring. + * + * Useful when performing a GPU reset method that affects + * multiple rings at the same time, such as an IP block soft + * reset. For example, a GFX IP block soft reset will affect + * every graphics and compute queue. + * + * This function should be called before such a reset. + * + * Prepare the affected rings before the reset, make sure to + * minimize collateral damage, and backup the contents of + * the rings. Then the caller can call the actual HW specific + * reset function. + * + * After the reset is complete, the caller should then call + * amdgpu_multi_ring_reset_helper_end() to restore the rings. + */ +void amdgpu_multi_ring_reset_helper_begin(const u32 ring_type_mask, + struct amdgpu_ring *guilty_ring, + struct amdgpu_fence *guilty_fence) +{ + struct amdgpu_device *adev = guilty_ring->adev; + struct amdgpu_fence *ring_guilty_fence; + struct amdgpu_ring *ring; + bool rings_busy; + int i; + u32 t; + + for (i = 0; i < adev->num_rings; ++i) { + ring = adev->rings[i]; + + if (!(BIT(ring->funcs->type) & ring_type_mask)) + continue; + + /* Don't accept new submissions on the ring. */ + if (amdgpu_ring_sched_ready(ring) && !drm_sched_is_stopped(&ring->sched)) + drm_sched_wqueue_stop(&ring->sched); + + /* + * Clear the preempt condition to stop the ring + * from starting its next submission. This ensures + * that only the currently executing submission + * can be rejected because of the reset and helps + * minimize collateral damage. + */ + if (ring->funcs->init_cond_exec) + amdgpu_ring_set_preempt_cond_exec(ring, false); + } + + /* Flush HDP cache so the GPU can see the updated COND_EXEC values */ + amdgpu_device_flush_hdp(adev, NULL); + + /* + * Give some time for non-guilty rings to finish their + * current submission, to try to minimize collateral damage. + * + * Note that this is just a best effort, but really there + * is no way to really know which ring is actually responsible + * because different rings may share resources, eg. a compute + * ring may hog shader engines, causing a graphics ring to hang. + */ + for (t = 0; t < adev->usec_timeout; t += 10000) { + rings_busy = false; + + /* Check if any of the non-guilty rings are busy */ + for (i = 0; i < adev->num_rings; ++i) { + ring = adev->rings[i]; + + if (!(BIT(ring->funcs->type) & ring_type_mask)) + continue; + + if (ring == guilty_ring) + continue; + + rings_busy |= + atomic_read(&ring->fence_drv.last_seq) != + READ_ONCE(ring->fence_drv.sync_seq); + } + + if (!rings_busy) + break; + + mdelay(10); + } + + for (i = 0; i < adev->num_rings; ++i) { + ring = adev->rings[i]; + + if (!(BIT(ring->funcs->type) & ring_type_mask)) + continue; + + /* + * Find guilty fences, ie. the fences that didn't signal + * on each ring. At this point there is no way to know + * which one is really responsible for the hang, and no + * way to save any of them, so we treat all of them as guilty. + */ + ring_guilty_fence = + ring == guilty_ring ? guilty_fence : + amdgpu_ring_find_guilty_fence(ring); + + /* + * Backup current contents of the ring. + * The helper takes care to only reemit unsignalled fences + * so we don't have to worry about that here. + */ + amdgpu_ring_reset_helper_begin(ring, ring_guilty_fence); + } +} + +/** + * amdgpu_multi_ring_reset_helper_end() - Prepare multiple rings for a reset. + * + * @ring_type_mask: Bitmask of affected ring types + * @guilty_ring: The ring which is guilty of causing a reset. + * @ret: Return code from the reset function. + * + * After calling amdgpu_multi_ring_reset_helper_begin() + * and executing the actual reset method, call this + * function to restore normal operation. + * + * In case the reset failed, this function should still + * be called to restore preemption state, but it won't attempt to + * fully restore the ring contents. + */ +int amdgpu_multi_ring_reset_helper_end(const u32 ring_type_mask, + struct amdgpu_ring *guilty_ring, int ret) +{ + struct amdgpu_device *adev = guilty_ring->adev; + struct amdgpu_ring *ring; + int i, r; + + /* Set preempt condition, rings are now allowed to execute submissions */ + for (i = 0; i < adev->num_rings; ++i) { + ring = adev->rings[i]; + + if (!(BIT(ring->funcs->type) & ring_type_mask)) + continue; + + if (ring->funcs->init_cond_exec) + amdgpu_ring_set_preempt_cond_exec(ring, true); + } + + /* Flush HDP cache so the GPU can see the updated COND_EXEC values */ + amdgpu_device_flush_hdp(adev, NULL); + + /* If the reset was unsuccessful, return without restoring anything else. */ + if (ret) + return ret; + + /* Restore contents of all rings */ + for (i = 0; i < adev->num_rings; ++i) { + ring = adev->rings[i]; + + if (!(BIT(ring->funcs->type) & ring_type_mask)) + continue; + + /* Restore contents of the ring */ + r = amdgpu_ring_reset_helper_end(ring, ring->guilty_fence); + if (r) { + dev_err(adev->dev, + "Failed to recover ring %s after soft reset\n", + ring->name); + return r; + } + } + + /* Accept submissions on all rings again */ + for (i = 0; i < adev->num_rings; ++i) { + ring = adev->rings[i]; + + if (!(BIT(ring->funcs->type) & ring_type_mask)) + continue; + + if (!amdgpu_ring_sched_ready(ring)) + continue; + + drm_sched_wqueue_start(&ring->sched); + } + + return 0; +} + bool amdgpu_ring_is_reset_type_supported(struct amdgpu_ring *ring, u32 reset_type) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h index 8f28b3bd7010..9d3934b4f106 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h @@ -314,6 +314,7 @@ struct amdgpu_ring { uint32_t *ring_backup; unsigned int ring_backup_entries_to_copy; bool reemit; + struct amdgpu_fence *guilty_fence; unsigned rptr_offs; u64 rptr_gpu_addr; u32 *rptr_cpu_addr; @@ -588,10 +589,17 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev); bool amdgpu_ring_sched_ready(struct amdgpu_ring *ring); void amdgpu_ring_backup_unprocessed_commands(struct amdgpu_ring *ring, struct amdgpu_fence *guilty_fence); +struct amdgpu_fence * +amdgpu_ring_find_guilty_fence(struct amdgpu_ring *ring); void amdgpu_ring_reset_helper_begin(struct amdgpu_ring *ring, struct amdgpu_fence *guilty_fence); int amdgpu_ring_reset_helper_end(struct amdgpu_ring *ring, struct amdgpu_fence *guilty_fence); +void amdgpu_multi_ring_reset_helper_begin(const u32 ring_type_mask, + struct amdgpu_ring *guilty_ring, + struct amdgpu_fence *guilty_fence); +int amdgpu_multi_ring_reset_helper_end(const u32 ring_type_mask, + struct amdgpu_ring *guilty_ring, int ret); bool amdgpu_ring_is_reset_type_supported(struct amdgpu_ring *ring, u32 reset_type); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c index 572a60e1b3cb..002fae3c380e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.c @@ -583,3 +583,42 @@ int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, amdgpu_gfx_rlc_init_microcode_v2_5(adev); return 0; } + +static const struct amdgpu_rlc_reg_funcs amdgpu_sriov_rlc_reg_funcs = { + .rreg32 = amdgpu_sriov_rreg, + .wreg32 = amdgpu_sriov_wreg, +}; + +static u32 +amdgpu_rlc_rreg(struct amdgpu_device *adev, u32 reg, u32 acc_flags, u32 hwip, + u32 xcc_id) +{ + return amdgpu_device_rreg(adev, reg, 0); +} + +static void +amdgpu_rlc_wreg(struct amdgpu_device *adev, u32 reg, u32 value, u32 acc_flags, + u32 hwip, u32 xcc_id) +{ + amdgpu_device_wreg(adev, reg, value, 0); +} + +static const struct amdgpu_rlc_reg_funcs amdgpu_rlc_reg_funcs = { + .rreg32 = amdgpu_rlc_rreg, + .wreg32 = amdgpu_rlc_wreg, +}; + +void amdgpu_early_init_rlc_reg_funcs(struct amdgpu_device *adev) +{ + adev->gfx.rlc.reg_funcs = &amdgpu_rlc_reg_funcs; +} + +void amdgpu_init_rlc_reg_funcs(struct amdgpu_device *adev) +{ + if (amdgpu_sriov_vf(adev) && + adev->gfx.rlc.funcs && + adev->gfx.rlc.rlcg_reg_access_supported) + adev->gfx.rlc.reg_funcs = &amdgpu_sriov_rlc_reg_funcs; + else + adev->gfx.rlc.reg_funcs = &amdgpu_rlc_reg_funcs; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h index e535534237a1..959d60c90dcd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_rlc.h @@ -262,6 +262,11 @@ struct amdgpu_rlc_funcs { bool (*is_rlcg_access_range)(struct amdgpu_device *adev, uint32_t reg); }; +struct amdgpu_rlc_reg_funcs { + u32 (*rreg32)(struct amdgpu_device *adev, u32 reg, u32 acc_flags, u32 hwip, u32 xcc_id); + void (*wreg32)(struct amdgpu_device *adev, u32 reg, u32 val, u32 acc_flags, u32 hwip, u32 xcc_id); +}; + struct amdgpu_rlcg_reg_access_ctrl { uint32_t scratch_reg0; uint32_t scratch_reg1; @@ -303,6 +308,7 @@ struct amdgpu_rlc { /* safe mode for updating CG/PG state */ bool in_safe_mode[AMDGPU_MAX_RLC_INSTANCES]; const struct amdgpu_rlc_funcs *funcs; + const struct amdgpu_rlc_reg_funcs *reg_funcs; /* for firmware data */ u32 save_and_restore_offset; @@ -374,4 +380,8 @@ void amdgpu_gfx_rlc_fini(struct amdgpu_device *adev); int amdgpu_gfx_rlc_init_microcode(struct amdgpu_device *adev, uint16_t version_major, uint16_t version_minor); + +void amdgpu_early_init_rlc_reg_funcs(struct amdgpu_device *adev); +void amdgpu_init_rlc_reg_funcs(struct amdgpu_device *adev); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.h new file mode 100644 index 000000000000..8c85c80fc119 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.h @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef AMDGPU_SA_H_ +#define AMDGPU_SA_H_ + +#include + +struct amdgpu_device; +struct amdgpu_bo; + +struct amdgpu_sa_manager { + struct drm_suballoc_manager base; + struct amdgpu_bo *bo; + uint64_t gpu_addr; + void *cpu_ptr; +}; + +static inline struct amdgpu_sa_manager * +to_amdgpu_sa_manager(struct drm_suballoc_manager *manager) +{ + return container_of(manager, struct amdgpu_sa_manager, base); +} + +static inline uint64_t amdgpu_sa_bo_gpu_addr(struct drm_suballoc *sa_bo) +{ + return to_amdgpu_sa_manager(sa_bo->manager)->gpu_addr + + drm_suballoc_soffset(sa_bo); +} + +static inline void *amdgpu_sa_bo_cpu_addr(struct drm_suballoc *sa_bo) +{ + return to_amdgpu_sa_manager(sa_bo->manager)->cpu_ptr + + drm_suballoc_soffset(sa_bo); +} + +int amdgpu_sa_bo_manager_init(struct amdgpu_device *adev, + struct amdgpu_sa_manager *sa_manager, + unsigned size, u32 align, u32 domain); +void amdgpu_sa_bo_manager_fini(struct amdgpu_device *adev, + struct amdgpu_sa_manager *sa_manager); +int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev, + struct amdgpu_sa_manager *sa_manager); +int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, + struct drm_suballoc **sa_bo, + unsigned int size); +void amdgpu_sa_bo_free(struct drm_suballoc **sa_bo, + struct dma_fence *fence); +#if defined(CONFIG_DEBUG_FS) +void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager, + struct seq_file *m); +u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m); +#endif +void amdgpu_debugfs_sa_init(struct amdgpu_device *adev); + +#endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 0eecfaa3a94c..8effb1158430 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -39,7 +39,7 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, struct amdgpu_fpriv *fpriv; struct amdgpu_ctx_mgr *mgr; struct amdgpu_ctx *ctx; - uint32_t id; + unsigned long id; int r; if (fd_empty(f)) @@ -50,10 +50,10 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, return r; mgr = &fpriv->ctx_mgr; - mutex_lock(&mgr->lock); - idr_for_each_entry(&mgr->ctx_handles, ctx, id) + xa_lock(&mgr->ctx_handles); + xa_for_each(&mgr->ctx_handles, id, ctx) amdgpu_ctx_priority_override(ctx, priority); - mutex_unlock(&mgr->lock); + xa_unlock(&mgr->ctx_handles); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c index fcd81242059e..fbac732f3e01 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.c @@ -553,10 +553,11 @@ static int amdgpu_sdma_soft_reset(struct amdgpu_device *adev, u32 instance_id) int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id, bool caller_handles_kernel_queues) { - int ret = 0; struct amdgpu_sdma_instance *sdma_instance = &adev->sdma.instance[instance_id]; struct amdgpu_ring *gfx_ring = &sdma_instance->ring; struct amdgpu_ring *page_ring = &sdma_instance->page; + struct amdgpu_fence *gfx_fence, *page_fence; + int ret = 0; if (amdgpu_sriov_vf(adev)) return -EOPNOTSUPP; @@ -569,9 +570,14 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id, * the reset is in progress. */ drm_sched_wqueue_stop(&gfx_ring->sched); + gfx_fence = amdgpu_ring_find_guilty_fence(gfx_ring); + amdgpu_ring_reset_helper_begin(gfx_ring, gfx_fence); - if (adev->sdma.has_page_queue) + if (adev->sdma.has_page_queue) { drm_sched_wqueue_stop(&page_ring->sched); + page_fence = amdgpu_ring_find_guilty_fence(page_ring); + amdgpu_ring_reset_helper_begin(page_ring, page_fence); + } } if (sdma_instance->funcs->stop_kernel_queue) { @@ -600,14 +606,19 @@ int amdgpu_sdma_reset_engine(struct amdgpu_device *adev, uint32_t instance_id, * to be submitted to the queues after the reset is complete. */ if (!ret) { - amdgpu_fence_driver_force_completion(gfx_ring, NULL); + ret = amdgpu_ring_reset_helper_end(gfx_ring, gfx_fence); + if (ret) + goto unlock; drm_sched_wqueue_start(&gfx_ring->sched); if (adev->sdma.has_page_queue) { - amdgpu_fence_driver_force_completion(page_ring, NULL); + ret = amdgpu_ring_reset_helper_end(page_ring, page_fence); + if (ret) + goto unlock; drm_sched_wqueue_start(&page_ring->sched); } } } +unlock: mutex_unlock(&sdma_instance->engine_reset_mutex); return ret; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h index 2bf365609775..4f4e56022c97 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sdma.h @@ -85,34 +85,6 @@ struct amdgpu_sdma_instance { const struct amdgpu_sdma_funcs *funcs; }; -enum amdgpu_sdma_ras_memory_id { - AMDGPU_SDMA_MBANK_DATA_BUF0 = 1, - AMDGPU_SDMA_MBANK_DATA_BUF1 = 2, - AMDGPU_SDMA_MBANK_DATA_BUF2 = 3, - AMDGPU_SDMA_MBANK_DATA_BUF3 = 4, - AMDGPU_SDMA_MBANK_DATA_BUF4 = 5, - AMDGPU_SDMA_MBANK_DATA_BUF5 = 6, - AMDGPU_SDMA_MBANK_DATA_BUF6 = 7, - AMDGPU_SDMA_MBANK_DATA_BUF7 = 8, - AMDGPU_SDMA_MBANK_DATA_BUF8 = 9, - AMDGPU_SDMA_MBANK_DATA_BUF9 = 10, - AMDGPU_SDMA_MBANK_DATA_BUF10 = 11, - AMDGPU_SDMA_MBANK_DATA_BUF11 = 12, - AMDGPU_SDMA_MBANK_DATA_BUF12 = 13, - AMDGPU_SDMA_MBANK_DATA_BUF13 = 14, - AMDGPU_SDMA_MBANK_DATA_BUF14 = 15, - AMDGPU_SDMA_MBANK_DATA_BUF15 = 16, - AMDGPU_SDMA_UCODE_BUF = 17, - AMDGPU_SDMA_RB_CMD_BUF = 18, - AMDGPU_SDMA_IB_CMD_BUF = 19, - AMDGPU_SDMA_UTCL1_RD_FIFO = 20, - AMDGPU_SDMA_UTCL1_RDBST_FIFO = 21, - AMDGPU_SDMA_UTCL1_WR_FIFO = 22, - AMDGPU_SDMA_DATA_LUT_FIFO = 23, - AMDGPU_SDMA_SPLIT_DAT_BUF = 24, - AMDGPU_SDMA_MEMORY_BLOCK_LAST, -}; - struct amdgpu_sdma_ras { struct amdgpu_ras_block_object ras_block; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h index 85724ec6aaf8..5324030a13f5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h @@ -28,6 +28,8 @@ #include #include +#include "amdgpu_userq_fence.h" + #undef TRACE_SYSTEM #define TRACE_SYSTEM amdgpu #define TRACE_INCLUDE_FILE amdgpu_trace @@ -582,6 +584,154 @@ TRACE_EVENT(amdgpu_reset_reg_dumps, __entry->value) ); +DECLARE_EVENT_CLASS(amdgpu_userq_queue, + TP_PROTO(struct amdgpu_usermode_queue *queue), + TP_ARGS(queue), + TP_STRUCT__entry( + __field(void *, queue) + __field(u64, doorbell_index) + __field(int, queue_type) + __field(int, state) + __field(u32, xcp_id) + ), + TP_fast_assign( + __entry->queue = queue; + __entry->doorbell_index = queue->doorbell_index; + __entry->queue_type = queue->queue_type; + __entry->state = queue->state; + __entry->xcp_id = queue->xcp_id; + ), + TP_printk("queue=%p, doorbell=%llu, type=%d, state=%d, xcp_id=%u", + __entry->queue, __entry->doorbell_index, + __entry->queue_type, __entry->state, __entry->xcp_id) +); +DEFINE_EVENT(amdgpu_userq_queue, amdgpu_userq_create_start, + TP_PROTO(struct amdgpu_usermode_queue *queue), + TP_ARGS(queue)); +DEFINE_EVENT(amdgpu_userq_queue, amdgpu_userq_destroy_start, + TP_PROTO(struct amdgpu_usermode_queue *queue), + TP_ARGS(queue)); +DECLARE_EVENT_CLASS(amdgpu_userq_queue_result, + TP_PROTO(struct amdgpu_usermode_queue *queue, int result), + TP_ARGS(queue, result), + TP_STRUCT__entry( + __field(void *, queue) + __field(u64, doorbell_index) + __field(int, queue_type) + __field(int, state) + __field(u32, xcp_id) + __field(int, result) + ), + TP_fast_assign( + __entry->queue = queue; + __entry->doorbell_index = queue->doorbell_index; + __entry->queue_type = queue->queue_type; + __entry->state = queue->state; + __entry->xcp_id = queue->xcp_id; + __entry->result = result; + ), + TP_printk("queue=%p, doorbell=%llu, type=%d, state=%d, xcp_id=%u, result=%d", + __entry->queue, __entry->doorbell_index, + __entry->queue_type, __entry->state, + __entry->xcp_id, __entry->result) +); +DEFINE_EVENT(amdgpu_userq_queue_result, amdgpu_userq_create_end, + TP_PROTO(struct amdgpu_usermode_queue *queue, int result), + TP_ARGS(queue, result)); +DEFINE_EVENT(amdgpu_userq_queue_result, amdgpu_userq_destroy_end, + TP_PROTO(struct amdgpu_usermode_queue *queue, int result), + TP_ARGS(queue, result)); + +TRACE_EVENT(amdgpu_userq_emit_fence, + TP_PROTO(struct device *device, struct amdgpu_usermode_queue *queue, struct amdgpu_userq_fence *fence), + TP_ARGS(device, queue, fence), + TP_STRUCT__entry( + __field(u64, fence_context) + __field(u64, fence_seqno) + __string(dev, dev_name(device)) + __field(u64, doorbell_index) + __field(u64, client_id) + __field(u32, queue_type) + ), + TP_fast_assign( + __entry->fence_context = fence->base.context; + __entry->fence_seqno = fence->base.seqno; + __assign_str(dev); + __entry->doorbell_index = queue->doorbell_index; + __entry->client_id = queue->userq_mgr->file->client_id; + __entry->queue_type = queue->queue_type; + ), + TP_printk("dev=%s, client_id=%llu, type=%u, doorbell=%llu, fence=%llu:%llu", + __get_str(dev), __entry->client_id, __entry->queue_type, __entry->doorbell_index, + __entry->fence_context, + __entry->fence_seqno) +); + +TRACE_EVENT(amdgpu_userq_wait_deps, + TP_PROTO(struct device *device, struct amdgpu_usermode_queue *queue, struct amdgpu_userq_fence *dep), + TP_ARGS(device, queue, dep), + TP_STRUCT__entry( + __field(u64, context) + __field(u64, dep_context) + __field(u64, dep_seqno) + __string(dev, dev_name(device)) + __field(u64, doorbell_index) + __field(u64, client_id) + __field(u32, queue_type) + ), + TP_fast_assign( + __assign_str(dev); + __entry->doorbell_index = queue->doorbell_index; + __entry->queue_type = queue->queue_type; + __entry->client_id = queue->userq_mgr->file->client_id; + __entry->context = queue->fence_drv->context; + __entry->dep_context = dep->base.context; + __entry->dep_seqno = dep->base.seqno; + ), + TP_printk("dev=%s, client_id=%llu, type=%u, doorbell=%llu, context=%llu depends on fence=%llu:%llu", + __get_str(dev), __entry->client_id, __entry->queue_type, __entry->doorbell_index, __entry->context, + __entry->dep_context, + __entry->dep_seqno) +); + +TRACE_EVENT(amdgpu_userq_state_start, + TP_PROTO(struct amdgpu_usermode_queue *queue), + TP_ARGS(queue), + TP_STRUCT__entry( + __field(u64, doorbell_index) + __field(u64, client_id) + __field(u32, queue_type) + __field(u32, from) + ), + TP_fast_assign( + __entry->doorbell_index = queue->doorbell_index; + __entry->queue_type = queue->queue_type; + __entry->client_id = queue->userq_mgr->file->client_id; + __entry->from = queue->state; + ), + TP_printk("client_id=%llu, type=%u, doorbell=%llu, from=%d", + __entry->client_id, __entry->queue_type, __entry->doorbell_index, __entry->from) +); + +TRACE_EVENT(amdgpu_userq_state_changed, + TP_PROTO(struct amdgpu_usermode_queue *queue, enum amdgpu_userq_state new_state), + TP_ARGS(queue, new_state), + TP_STRUCT__entry( + __field(u64, doorbell_index) + __field(u64, client_id) + __field(u32, queue_type) + __field(u32, to) + ), + TP_fast_assign( + __entry->doorbell_index = queue->doorbell_index; + __entry->queue_type = queue->queue_type; + __entry->client_id = queue->userq_mgr->file->client_id; + __entry->to = new_state; + ), + TP_printk("client_id=%llu, type=%u, doorbell=%llu, to=%d", + __entry->client_id, __entry->queue_type, __entry->doorbell_index, __entry->to) +); + #undef AMDGPU_JOB_GET_TIMELINE_NAME #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 16c060badaee..b10b0878df37 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -208,9 +208,10 @@ static int amdgpu_ttm_map_buffer(struct amdgpu_ttm_buffer_entity *entity, void *cpu_addr; uint64_t flags; int r; + const u64 GTT_MAX_PAGES = (AMDGPU_GTT_MAX_TRANSFER_SIZE >> PAGE_SHIFT); BUG_ON(adev->mman.buffer_funcs->copy_max_bytes < - AMDGPU_GTT_MAX_TRANSFER_SIZE * 8); + GTT_MAX_PAGES * AMDGPU_GPU_PAGES_IN_CPU_PAGE * 8); if (WARN_ON(mem->mem_type == AMDGPU_PL_PREEMPT)) return -EINVAL; @@ -230,7 +231,7 @@ static int amdgpu_ttm_map_buffer(struct amdgpu_ttm_buffer_entity *entity, offset = mm_cur->start & ~PAGE_MASK; num_pages = PFN_UP(*size + offset); - num_pages = min_t(uint32_t, num_pages, AMDGPU_GTT_MAX_TRANSFER_SIZE); + num_pages = min_t(uint32_t, num_pages, GTT_MAX_PAGES); *size = min(*size, (uint64_t)num_pages * PAGE_SIZE - offset); @@ -2033,6 +2034,7 @@ static int amdgpu_ttm_buffer_entity_init(struct amdgpu_gtt_mgr *mgr, u32 num_gart_windows) { int i, r, num_pages; + const u64 GTT_MAX_PAGES = (AMDGPU_GTT_MAX_TRANSFER_SIZE >> PAGE_SHIFT); r = drm_sched_entity_init(&entity->base, prio, scheds, num_schedulers, NULL); if (r) @@ -2045,7 +2047,7 @@ static int amdgpu_ttm_buffer_entity_init(struct amdgpu_gtt_mgr *mgr, if (num_gart_windows == 0) return 0; - num_pages = num_gart_windows * AMDGPU_GTT_MAX_TRANSFER_SIZE; + num_pages = num_gart_windows * GTT_MAX_PAGES; r = amdgpu_gtt_mgr_alloc_entries(mgr, &entity->gart_node, num_pages, DRM_MM_INSERT_BEST); if (r) { @@ -2056,7 +2058,7 @@ static int amdgpu_ttm_buffer_entity_init(struct amdgpu_gtt_mgr *mgr, for (i = 0; i < num_gart_windows; i++) { entity->gart_window_offs[i] = amdgpu_gtt_node_to_byte_offset(&entity->gart_node) + - i * AMDGPU_GTT_MAX_TRANSFER_SIZE * PAGE_SIZE; + i * GTT_MAX_PAGES * PAGE_SIZE; } return 0; @@ -2118,18 +2120,23 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) /* Change the size here instead of the init above so only lpfn is affected */ amdgpu_ttm_disable_buffer_funcs(adev); #ifdef CONFIG_64BIT -#ifdef CONFIG_X86 - if (adev->gmc.xgmi.connected_to_cpu) - adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base, - adev->gmc.visible_vram_size); - - else if (adev->gmc.is_app_apu) + if (adev->gmc.xgmi.connected_to_cpu) { + void *kaddr = devm_memremap(adev->dev, adev->gmc.aper_base, + adev->gmc.visible_vram_size, + MEMREMAP_WB); + if (IS_ERR(kaddr)) + return PTR_ERR(kaddr); + adev->mman.aper_base_kaddr = (__force void __iomem *)kaddr; + } else if (adev->gmc.is_app_apu) { DRM_DEBUG_DRIVER( "No need to ioremap when real vram size is 0\n"); - else -#endif - adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base, - adev->gmc.visible_vram_size); + } else { + adev->mman.aper_base_kaddr = devm_ioremap_wc(adev->dev, + adev->gmc.aper_base, + adev->gmc.visible_vram_size); + if (!adev->mman.aper_base_kaddr) + return -ENOMEM; + } #endif amdgpu_ttm_init_vram_resv_regions(adev); @@ -2187,7 +2194,7 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) return r; } - /* Create a boorbell page for kernel usages */ + /* Create a doorbell page for kernel usages */ r = amdgpu_doorbell_create_kernel_doorbells(adev); if (r) { dev_err(adev->dev, "Failed to initialize kernel doorbells.\n"); @@ -2246,8 +2253,6 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) */ void amdgpu_ttm_fini(struct amdgpu_device *adev) { - int idx; - if (!adev->mman.initialized) return; @@ -2270,14 +2275,7 @@ void amdgpu_ttm_fini(struct amdgpu_device *adev) amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_FW_VRAM_USAGE); amdgpu_ttm_unmark_vram_reserved(adev, AMDGPU_RESV_DRV_VRAM_USAGE); - if (drm_dev_enter(adev_to_drm(adev), &idx)) { - - if (adev->mman.aper_base_kaddr) - iounmap(adev->mman.aper_base_kaddr); - adev->mman.aper_base_kaddr = NULL; - - drm_dev_exit(idx); - } + adev->mman.aper_base_kaddr = NULL; if (!adev->gmc.is_app_apu) amdgpu_vram_mgr_fini(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 2d72fa217274..ff9e2e346609 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -39,7 +39,7 @@ #define AMDGPU_PL_MMIO_REMAP (TTM_PL_PRIV + 5) #define __AMDGPU_PL_NUM (TTM_PL_PRIV + 6) -#define AMDGPU_GTT_MAX_TRANSFER_SIZE 1024 +#define AMDGPU_GTT_MAX_TRANSFER_SIZE (1ULL << 22) extern const struct attribute_group amdgpu_vram_mgr_attr_group; extern const struct attribute_group amdgpu_gtt_mgr_attr_group; @@ -140,6 +140,7 @@ int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size); void amdgpu_gtt_mgr_fini(struct amdgpu_device *adev); int amdgpu_preempt_mgr_init(struct amdgpu_device *adev); void amdgpu_preempt_mgr_fini(struct amdgpu_device *adev); +void amdgpu_preempt_mgr_sysfs_fini(struct amdgpu_device *adev); int amdgpu_vram_mgr_init(struct amdgpu_device *adev); void amdgpu_vram_mgr_fini(struct amdgpu_device *adev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c index b8ed931f8a40..2a5f5e6188bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.c @@ -97,7 +97,6 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev, { struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - struct amdgpu_ras_eeprom_control *control = &con->eeprom_control; unsigned int error_query_mode; int ret = 0; unsigned long err_count; @@ -118,77 +117,66 @@ void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev, err_data->err_addr_len = adev->umc.max_ras_err_cnt_per_query; mutex_lock(&con->page_retirement_lock); - if (!amdgpu_ras_smu_eeprom_supported(adev)) { - ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc)); - if (ret == -EOPNOTSUPP && - error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { - if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && - adev->umc.ras->ras_block.hw_ops->query_ras_error_count) - adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev, - ras_error_status); + ret = amdgpu_dpm_get_ecc_info(adev, (void *)&(con->umc_ecc)); + if (ret == -EOPNOTSUPP && + error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY) { + if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && + adev->umc.ras->ras_block.hw_ops->query_ras_error_count) + adev->umc.ras->ras_block.hw_ops->query_ras_error_count(adev, + ras_error_status); - if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && - adev->umc.ras->ras_block.hw_ops->query_ras_error_address && - adev->umc.max_ras_err_cnt_per_query) { - kfree(err_data->err_addr); - err_data->err_addr = - kzalloc_objs(struct eeprom_table_record, - adev->umc.max_ras_err_cnt_per_query); + if (adev->umc.ras && adev->umc.ras->ras_block.hw_ops && + adev->umc.ras->ras_block.hw_ops->query_ras_error_address && + adev->umc.max_ras_err_cnt_per_query) { + err_data->err_addr = + kzalloc_objs(struct eeprom_table_record, + adev->umc.max_ras_err_cnt_per_query); - /* still call query_ras_error_address to clear error status - * even NOMEM error is encountered - */ - if (!err_data->err_addr) - dev_warn(adev->dev, - "Failed to alloc memory for umc error address record!\n"); - else - err_data->err_addr_len = - adev->umc.max_ras_err_cnt_per_query; + /* still call query_ras_error_address to clear error status + * even NOMEM error is encountered + */ + if (!err_data->err_addr) + dev_warn(adev->dev, + "Failed to alloc memory for umc error address record!\n"); + else + err_data->err_addr_len = + adev->umc.max_ras_err_cnt_per_query; - /* umc query_ras_error_address is also responsible for clearing - * error status - */ - adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev, - ras_error_status); - } - } else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY || - (!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) { - if (adev->umc.ras && - adev->umc.ras->ecc_info_query_ras_error_count) - adev->umc.ras->ecc_info_query_ras_error_count(adev, - ras_error_status); - - if (adev->umc.ras && - adev->umc.ras->ecc_info_query_ras_error_address && - adev->umc.max_ras_err_cnt_per_query) { - kfree(err_data->err_addr); - err_data->err_addr = - kzalloc_objs(struct eeprom_table_record, - adev->umc.max_ras_err_cnt_per_query); - - /* still call query_ras_error_address to clear error status - * even NOMEM error is encountered - */ - if (!err_data->err_addr) - dev_warn(adev->dev, - "Failed to alloc memory for umc error address record!\n"); - else - err_data->err_addr_len = - adev->umc.max_ras_err_cnt_per_query; - - /* umc query_ras_error_address is also responsible for clearing - * error status - */ - adev->umc.ras->ecc_info_query_ras_error_address(adev, - ras_error_status); - } + /* umc query_ras_error_address is also responsible for clearing + * error status + */ + adev->umc.ras->ras_block.hw_ops->query_ras_error_address(adev, + ras_error_status); } - } else { - if (!amdgpu_ras_eeprom_update_record_num(control)) { - err_data->err_addr_cnt = err_data->de_count = - control->ras_num_recs - control->ras_num_recs_old; - amdgpu_ras_eeprom_read_idx(control, err_data->err_addr, - control->ras_num_recs_old, err_data->de_count); + } else if (error_query_mode == AMDGPU_RAS_FIRMWARE_ERROR_QUERY || + (!ret && error_query_mode == AMDGPU_RAS_DIRECT_ERROR_QUERY)) { + if (adev->umc.ras && + adev->umc.ras->ecc_info_query_ras_error_count) + adev->umc.ras->ecc_info_query_ras_error_count(adev, + ras_error_status); + + if (adev->umc.ras && + adev->umc.ras->ecc_info_query_ras_error_address && + adev->umc.max_ras_err_cnt_per_query) { + err_data->err_addr = + kcalloc(adev->umc.max_ras_err_cnt_per_query, + sizeof(struct eeprom_table_record), GFP_KERNEL); + + /* still call query_ras_error_address to clear error status + * even NOMEM error is encountered + */ + if (!err_data->err_addr) + dev_warn(adev->dev, + "Failed to alloc memory for umc error address record!\n"); + else + err_data->err_addr_len = + adev->umc.max_ras_err_cnt_per_query; + + /* umc query_ras_error_address is also responsible for clearing + * error status + */ + adev->umc.ras->ecc_info_query_ras_error_address(adev, + ras_error_status); } } @@ -276,7 +264,7 @@ int amdgpu_umc_pasid_poison_handler(struct amdgpu_device *adev, } amdgpu_ras_error_data_fini(&err_data); - } else if (amdgpu_uniras_enabled(adev)) { + } else { struct ras_ih_info ih_info = {0}; ih_info.block = block; @@ -285,17 +273,6 @@ int amdgpu_umc_pasid_poison_handler(struct amdgpu_device *adev, ih_info.pasid_fn = pasid_fn; ih_info.data = data; amdgpu_ras_mgr_handle_consumer_interrupt(adev, &ih_info); - } else { - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - int ret; - - ret = amdgpu_ras_put_poison_req(adev, - block, pasid, pasid_fn, data, reset); - if (!ret) { - atomic_inc(&con->page_retirement_req_cnt); - atomic_inc(&con->poison_consumption_count); - wake_up(&con->page_retirement_wq); - } } } else { if (adev->virt.ops && adev->virt.ops->ras_poison_handler) @@ -512,129 +489,3 @@ int amdgpu_umc_loop_channels(struct amdgpu_device *adev, return 0; } - -int amdgpu_umc_update_ecc_status(struct amdgpu_device *adev, - uint64_t status, uint64_t ipid, uint64_t addr) -{ - if (adev->umc.ras->update_ecc_status) - return adev->umc.ras->update_ecc_status(adev, - status, ipid, addr); - return 0; -} - -int amdgpu_umc_logs_ecc_err(struct amdgpu_device *adev, - struct radix_tree_root *ecc_tree, struct ras_ecc_err *ecc_err) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - struct ras_ecc_log_info *ecc_log; - int ret; - - ecc_log = &con->umc_ecc_log; - - mutex_lock(&ecc_log->lock); - ret = radix_tree_insert(ecc_tree, ecc_err->pa_pfn, ecc_err); - if (!ret) - radix_tree_tag_set(ecc_tree, - ecc_err->pa_pfn, UMC_ECC_NEW_DETECTED_TAG); - mutex_unlock(&ecc_log->lock); - - return ret; -} - -int amdgpu_umc_pages_in_a_row(struct amdgpu_device *adev, - struct ras_err_data *err_data, uint64_t pa_addr) -{ - struct ta_ras_query_address_output addr_out; - - /* reinit err_data */ - err_data->err_addr_cnt = 0; - err_data->err_addr_len = adev->umc.retire_unit; - - addr_out.pa.pa = pa_addr; - if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr) - return adev->umc.ras->convert_ras_err_addr(adev, err_data, NULL, - &addr_out, false); - else - return -EINVAL; -} - -int amdgpu_umc_lookup_bad_pages_in_a_row(struct amdgpu_device *adev, - uint64_t pa_addr, uint64_t *pfns, int len) -{ - int i, ret; - struct ras_err_data err_data; - - err_data.err_addr = kzalloc_objs(struct eeprom_table_record, - adev->umc.retire_unit); - if (!err_data.err_addr) { - dev_warn(adev->dev, "Failed to alloc memory in bad page lookup!\n"); - return 0; - } - - ret = amdgpu_umc_pages_in_a_row(adev, &err_data, pa_addr); - if (ret) - goto out; - - for (i = 0; i < adev->umc.retire_unit; i++) { - if (i >= len) - goto out; - - pfns[i] = err_data.err_addr[i].retired_page; - } - ret = i; - adev->umc.err_addr_cnt = err_data.err_addr_cnt; - -out: - kfree(err_data.err_addr); - return ret; -} - -int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev, - uint64_t err_addr, uint32_t ch, uint32_t umc, - uint32_t node, uint32_t socket, - struct ta_ras_query_address_output *addr_out, bool dump_addr) -{ - struct ta_ras_query_address_input addr_in; - int ret; - - memset(&addr_in, 0, sizeof(addr_in)); - addr_in.ma.err_addr = err_addr; - addr_in.ma.ch_inst = ch; - addr_in.ma.umc_inst = umc; - addr_in.ma.node_inst = node; - addr_in.ma.socket_id = socket; - - if (adev->umc.ras && adev->umc.ras->convert_ras_err_addr) { - ret = adev->umc.ras->convert_ras_err_addr(adev, NULL, &addr_in, - addr_out, dump_addr); - if (ret) - return ret; - } else { - return 0; - } - - return 0; -} - -int amdgpu_umc_pa2mca(struct amdgpu_device *adev, - uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps) -{ - struct ta_ras_query_address_input addr_in; - struct ta_ras_query_address_output addr_out; - int ret; - - /* nps: the pa belongs to */ - addr_in.pa.pa = pa | ((uint64_t)nps << 58); - addr_in.addr_type = TA_RAS_PA_TO_MCA; - ret = psp_ras_query_address(&adev->psp, &addr_in, &addr_out); - if (ret) { - dev_warn(adev->dev, "Failed to query RAS MCA address for 0x%llx", - pa); - - return ret; - } - - *mca = addr_out.ma.err_addr; - - return 0; -} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h index 8494a55ebf76..cf06d5f856f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_umc.h @@ -103,18 +103,7 @@ struct amdgpu_umc_ras { void *ras_error_status); bool (*check_ecc_err_status)(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, void *ras_error_status); - int (*update_ecc_status)(struct amdgpu_device *adev, - uint64_t status, uint64_t ipid, uint64_t addr); - int (*convert_ras_err_addr)(struct amdgpu_device *adev, - struct ras_err_data *err_data, - struct ta_ras_query_address_input *addr_in, - struct ta_ras_query_address_output *addr_out, - bool dump_addr); - uint32_t (*get_die_id_from_pa)(struct amdgpu_device *adev, - uint64_t mca_addr, uint64_t retired_page); void (*get_retire_flip_bits)(struct amdgpu_device *adev); - void (*mca_ipid_parse)(struct amdgpu_device *adev, uint64_t ipid, - uint32_t *did, uint32_t *ch, uint32_t *umc_inst, uint32_t *sid); }; struct amdgpu_umc_funcs { @@ -179,21 +168,6 @@ int amdgpu_umc_page_retirement_mca(struct amdgpu_device *adev, int amdgpu_umc_loop_channels(struct amdgpu_device *adev, umc_func func, void *data); -int amdgpu_umc_update_ecc_status(struct amdgpu_device *adev, - uint64_t status, uint64_t ipid, uint64_t addr); -int amdgpu_umc_logs_ecc_err(struct amdgpu_device *adev, - struct radix_tree_root *ecc_tree, struct ras_ecc_err *ecc_err); - void amdgpu_umc_handle_bad_pages(struct amdgpu_device *adev, void *ras_error_status); -int amdgpu_umc_pages_in_a_row(struct amdgpu_device *adev, - struct ras_err_data *err_data, uint64_t pa_addr); -int amdgpu_umc_lookup_bad_pages_in_a_row(struct amdgpu_device *adev, - uint64_t pa_addr, uint64_t *pfns, int len); -int amdgpu_umc_mca_to_addr(struct amdgpu_device *adev, - uint64_t err_addr, uint32_t ch, uint32_t umc, - uint32_t node, uint32_t socket, - struct ta_ras_query_address_output *addr_out, bool dump_addr); -int amdgpu_umc_pa2mca(struct amdgpu_device *adev, - uint64_t pa, uint64_t *mca, enum amdgpu_memory_partition nps); #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 91554e7c092c..82c8809d1d9c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -33,6 +33,7 @@ #include "amdgpu_userq.h" #include "amdgpu_hmm.h" #include "amdgpu_userq_fence.h" +#include "amdgpu_trace.h" u32 amdgpu_userq_get_supported_ip_mask(struct amdgpu_device *adev) { @@ -88,14 +89,7 @@ static void amdgpu_userq_mgr_reset_work(struct work_struct *work) container_of(work, struct amdgpu_userq_mgr, reset_work); struct amdgpu_device *adev = uq_mgr->adev; - const int queue_types[] = { - AMDGPU_RING_TYPE_COMPUTE, - AMDGPU_RING_TYPE_GFX, - AMDGPU_RING_TYPE_SDMA - }; - const int num_queue_types = ARRAY_SIZE(queue_types); - bool gpu_reset = false; - int i, r; + struct amdgpu_reset_context reset_context; if (unlikely(adev->debug_disable_gpu_ring_reset)) { dev_err(adev->dev, "userq reset disabled by debug mask\n"); @@ -109,42 +103,15 @@ static void amdgpu_userq_mgr_reset_work(struct work_struct *work) if (!amdgpu_gpu_recovery) return; - /* - * Iterate through all queue types to detect and reset problematic queues - * Process each queue type in the defined order - */ - for (i = 0; i < num_queue_types; i++) { - int ring_type = queue_types[i]; - const struct amdgpu_userq_funcs *funcs = - adev->userq_funcs[ring_type]; + memset(&reset_context, 0, sizeof(reset_context)); - if (!amdgpu_userq_is_reset_type_supported(adev, ring_type, - AMDGPU_RESET_TYPE_PER_QUEUE)) - continue; + reset_context.method = AMD_RESET_METHOD_NONE; + reset_context.reset_req_dev = adev; + reset_context.src = AMDGPU_RESET_SRC_USERQ; + set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); + /*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/ - if (atomic_read(&uq_mgr->userq_count[ring_type]) > 0 && - funcs && funcs->detect_and_reset) { - r = funcs->detect_and_reset(adev, ring_type); - if (r) { - gpu_reset = true; - break; - } - } - } - - if (gpu_reset) { - struct amdgpu_reset_context reset_context; - - memset(&reset_context, 0, sizeof(reset_context)); - - reset_context.method = AMD_RESET_METHOD_NONE; - reset_context.reset_req_dev = adev; - reset_context.src = AMDGPU_RESET_SRC_USERQ; - set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); - /*set_bit(AMDGPU_SKIP_COREDUMP, &reset_context.flags);*/ - - amdgpu_device_gpu_recover(adev, NULL, &reset_context); - } + amdgpu_device_gpu_recover(adev, NULL, &reset_context); } static void amdgpu_userq_hang_detect_work(struct work_struct *work) @@ -152,12 +119,45 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work) struct amdgpu_usermode_queue *queue = container_of(work, struct amdgpu_usermode_queue, hang_detect_work.work); + struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr; + struct amdgpu_device *adev = uq_mgr->adev; + const struct amdgpu_userq_funcs *userq_funcs = + adev->userq_funcs[queue->queue_type]; + bool gpu_reset = false; + + if (unlikely(adev->debug_disable_gpu_ring_reset)) { + dev_err(adev->dev, "userq reset disabled by debug mask\n"); + return; + } + + /* + * If GPU recovery feature is disabled system-wide, + * skip all reset detection logic + */ + if (!amdgpu_gpu_recovery) + return; + + if (amdgpu_userq_is_reset_type_supported(adev, queue->queue_type, + AMDGPU_RESET_TYPE_PER_QUEUE)) { + int r; + + if (queue->queue_type == AMDGPU_HW_IP_COMPUTE) + r = amdgpu_gfx_reset_mes_compute(adev, NULL, NULL, + queue, NULL, NULL); + else + r = userq_funcs->reset(queue); + if (r) + gpu_reset = true; + } else { + gpu_reset = true; + } /* * Don't schedule the work here! Scheduling or queue work from one reset * handler to another is illegal if you don't take extra precautions! */ - amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work); + if (gpu_reset) + amdgpu_userq_mgr_reset_work(&queue->userq_mgr->reset_work); } /* @@ -293,11 +293,15 @@ static int amdgpu_userq_preempt_helper(struct amdgpu_usermode_queue *queue) int r; if (queue->state == AMDGPU_USERQ_STATE_MAPPED) { + trace_amdgpu_userq_state_start(queue); + r = userq_funcs->preempt(queue); if (r) { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG); queue->state = AMDGPU_USERQ_STATE_HUNG; return r; } else { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_PREEMPTED); queue->state = AMDGPU_USERQ_STATE_PREEMPTED; } } @@ -313,10 +317,14 @@ static int amdgpu_userq_restore_helper(struct amdgpu_usermode_queue *queue) int r = 0; if (queue->state == AMDGPU_USERQ_STATE_PREEMPTED) { + trace_amdgpu_userq_state_start(queue); + r = userq_funcs->restore(queue); if (r) { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG); queue->state = AMDGPU_USERQ_STATE_HUNG; } else { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED); queue->state = AMDGPU_USERQ_STATE_MAPPED; } } @@ -334,12 +342,15 @@ static int amdgpu_userq_unmap_helper(struct amdgpu_usermode_queue *queue) if ((queue->state == AMDGPU_USERQ_STATE_MAPPED) || (queue->state == AMDGPU_USERQ_STATE_PREEMPTED)) { + trace_amdgpu_userq_state_start(queue); r = userq_funcs->unmap(queue); if (r) { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG); queue->state = AMDGPU_USERQ_STATE_HUNG; return r; } else { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_UNMAPPED); queue->state = AMDGPU_USERQ_STATE_UNMAPPED; } } @@ -356,11 +367,15 @@ static int amdgpu_userq_map_helper(struct amdgpu_usermode_queue *queue) int r; if (queue->state == AMDGPU_USERQ_STATE_UNMAPPED) { + trace_amdgpu_userq_state_start(queue); + r = userq_funcs->map(queue); if (r) { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG); queue->state = AMDGPU_USERQ_STATE_HUNG; return r; } else { + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED); queue->state = AMDGPU_USERQ_STATE_MAPPED; } } @@ -507,6 +522,8 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que const struct amdgpu_userq_funcs *uq_funcs = adev->userq_funcs[queue->queue_type]; int r = 0; + trace_amdgpu_userq_destroy_start(queue); + cancel_delayed_work_sync(&uq_mgr->resume_work); /* Cancel any pending hang detection work and cleanup */ @@ -532,6 +549,7 @@ amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_que amdgpu_bo_unreserve(queue->db_obj.obj); amdgpu_bo_unref(&queue->db_obj.obj); + trace_amdgpu_userq_destroy_end(queue, r); kfree(queue); pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); @@ -629,6 +647,8 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) queue->queue_type = args->in.ip_type; queue->vm = &fpriv->vm; queue->priority = priority; + queue->xcp_id = (fpriv->xcp_id != AMDGPU_XCP_NO_PARTITION) ? + fpriv->xcp_id : 0; queue->userq_mgr = uq_mgr; INIT_DELAYED_WORK(&queue->hang_detect_work, amdgpu_userq_hang_detect_work); @@ -671,6 +691,8 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) } queue->doorbell_index = index; + queue->doorbell_offset = (u32)args->in.doorbell_offset; + trace_amdgpu_userq_create_start(queue); r = uq_funcs->mqd_create(queue, &args->in); if (r) { drm_file_err(uq_mgr->file, "Failed to create Queue\n"); @@ -680,8 +702,8 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) /* Update VM owner at userq submit-time for page-fault attribution. */ amdgpu_vm_set_task_info(&fpriv->vm); - r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, - GFP_KERNEL)); + r = xa_insert_irq(&adev->userq_doorbell_xa, index, queue, + GFP_KERNEL); if (r) goto clean_mqd; @@ -694,6 +716,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) r = amdgpu_userq_map_helper(queue); if (r) { drm_file_err(uq_mgr->file, "Failed to map Queue\n"); + trace_amdgpu_userq_create_end(queue, r); mutex_unlock(&uq_mgr->userq_mutex); goto erase_doorbell; } @@ -710,11 +733,13 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) * This drops the last reference which should take care of * all cleanup. */ + trace_amdgpu_userq_create_end(queue, r); amdgpu_userq_put(queue); return r; } amdgpu_debugfs_userq_init(filp, queue, qid); + trace_amdgpu_userq_create_end(queue, 0); args->out.queue_id = qid; return 0; @@ -730,6 +755,7 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args) free_fence_drv: amdgpu_userq_fence_driver_free(queue); free_queue: + trace_amdgpu_userq_create_end(queue, r); kfree(queue); err_pm_runtime: pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); @@ -862,16 +888,10 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data, static int amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) { - struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); - struct amdgpu_vm *vm = &fpriv->vm; struct amdgpu_usermode_queue *queue; unsigned long queue_id; int ret = 0, r; - - if (amdgpu_bo_reserve(vm->root.bo, false)) - return false; - mutex_lock(&uq_mgr->userq_mutex); /* Resume all the queues for this process */ xa_for_each(&uq_mgr->userq_xa, queue_id, queue) { @@ -879,6 +899,7 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) if (!amdgpu_userq_buffer_vas_mapped(queue)) { drm_file_err(uq_mgr->file, "trying restore queue without va mapping\n"); + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_INVALID_VA); queue->state = AMDGPU_USERQ_STATE_INVALID_VA; continue; } @@ -886,10 +907,8 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr) r = amdgpu_userq_map_helper(queue); if (r) ret = r; - } mutex_unlock(&uq_mgr->userq_mutex); - amdgpu_bo_unreserve(vm->root.bo); if (ret) drm_file_err(uq_mgr->file, @@ -923,7 +942,8 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec, spin_unlock(&vm->individual_lock); bo = bo_va->base.bo; - ret = drm_exec_prepare_obj(exec, &bo->tbo.base, 2); + ret = drm_exec_prepare_obj(exec, &bo->tbo.base, + TTM_NUM_MOVE_FENCES + 1); if (unlikely(ret)) return ret; @@ -946,7 +966,7 @@ amdgpu_userq_bo_validate(struct amdgpu_device *adev, struct drm_exec *exec, /* Make sure the whole VM is ready to be used */ static int -amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr) +amdgpu_userq_vm_validate_and_restore_queue(struct amdgpu_userq_mgr *uq_mgr) { struct amdgpu_fpriv *fpriv = uq_mgr_to_fpriv(uq_mgr); bool invalidated = false, new_addition = false; @@ -1072,8 +1092,12 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr) dma_fence_wait(vm->last_update, false); ret = amdgpu_evf_mgr_rearm(&fpriv->evf_mgr, &exec); - if (ret) + if (ret) { drm_file_err(uq_mgr->file, "Failed to replace eviction fence\n"); + goto unlock_all; + } + + ret = amdgpu_userq_restore_all(uq_mgr); unlock_all: drm_exec_fini(&exec); @@ -1099,18 +1123,34 @@ static void amdgpu_userq_restore_worker(struct work_struct *work) if (!dma_fence_is_signaled(ev_fence)) goto put_fence; - ret = amdgpu_userq_vm_validate(uq_mgr); + ret = amdgpu_userq_vm_validate_and_restore_queue(uq_mgr); if (ret) { drm_file_err(uq_mgr->file, "Failed to validate BOs to restore ret=%d\n", ret); goto put_fence; } - amdgpu_userq_restore_all(uq_mgr); - put_fence: dma_fence_put(ev_fence); } +void amdgpu_userq_process_reset_irq(struct amdgpu_device *adev, + u32 pasid, u32 doorbell_offset) +{ + struct xarray *xa = &adev->userq_doorbell_xa; + struct amdgpu_usermode_queue *queue; + unsigned long flags, idx; + + xa_lock_irqsave(xa, flags); + xa_for_each(xa, idx, queue) { + if (queue->vm && queue->vm->pasid == pasid && + queue->doorbell_offset == doorbell_offset) { + amdgpu_userq_start_hang_detect_work(queue); + break; + } + } + xa_unlock_irqrestore(xa, flags); +} + static int amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr) { @@ -1166,6 +1206,7 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f xa_init_flags(&userq_mgr->userq_xa, XA_FLAGS_ALLOC); userq_mgr->adev = adev; userq_mgr->file = file_priv; + mutex_init(&userq_mgr->proc_ctx_lock); INIT_DELAYED_WORK(&userq_mgr->resume_work, amdgpu_userq_restore_worker); INIT_WORK(&userq_mgr->reset_work, amdgpu_userq_mgr_reset_work); @@ -1219,6 +1260,11 @@ void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr) */ cancel_work_sync(&userq_mgr->reset_work); + amdgpu_bo_free_kernel(&userq_mgr->proc_ctx_obj.obj, + &userq_mgr->proc_ctx_obj.gpu_addr, + &userq_mgr->proc_ctx_obj.cpu_ptr); + + mutex_destroy(&userq_mgr->proc_ctx_lock); mutex_destroy(&userq_mgr->userq_mutex); } @@ -1370,12 +1416,14 @@ void amdgpu_userq_pre_reset(struct amdgpu_device *adev) if (queue->state != AMDGPU_USERQ_STATE_MAPPED) continue; + trace_amdgpu_userq_state_start(queue); userq_funcs = adev->userq_funcs[queue->queue_type]; userq_funcs->unmap(queue); /* just mark all queues as hung at this point. * if unmap succeeds, we could map again * in amdgpu_userq_post_reset() if vram is not lost */ + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_HUNG); queue->state = AMDGPU_USERQ_STATE_HUNG; amdgpu_userq_fence_driver_force_completion(queue); } @@ -1394,6 +1442,8 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost) xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) { if (queue->state == AMDGPU_USERQ_STATE_HUNG && !vram_lost) { + trace_amdgpu_userq_state_start(queue); + userq_funcs = adev->userq_funcs[queue->queue_type]; /* Re-map queue */ r = userq_funcs->map(queue); @@ -1401,6 +1451,7 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost) dev_err(adev->dev, "Failed to remap queue %ld\n", queue_id); continue; } + trace_amdgpu_userq_state_changed(queue, AMDGPU_USERQ_STATE_MAPPED); queue->state = AMDGPU_USERQ_STATE_MAPPED; } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h index d1751febaefe..61e5f8a06eb2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h @@ -53,6 +53,7 @@ struct amdgpu_usermode_queue { enum amdgpu_userq_state state; uint64_t doorbell_handle; uint64_t doorbell_index; + u32 doorbell_offset; uint64_t flags; struct amdgpu_mqd_prop *userq_prop; struct amdgpu_userq_mgr *userq_mgr; @@ -111,8 +112,7 @@ struct amdgpu_userq_funcs { int (*map)(struct amdgpu_usermode_queue *queue); int (*preempt)(struct amdgpu_usermode_queue *queue); int (*restore)(struct amdgpu_usermode_queue *queue); - int (*detect_and_reset)(struct amdgpu_device *adev, - int queue_type); + int (*reset)(struct amdgpu_usermode_queue *queue); }; /* Usermode queues for gfx */ @@ -127,6 +127,8 @@ struct amdgpu_userq_mgr { struct amdgpu_device *adev; struct delayed_work resume_work; struct drm_file *file; + struct mutex proc_ctx_lock; + struct amdgpu_userq_obj proc_ctx_obj; /** * @reset_work: @@ -177,6 +179,16 @@ int amdgpu_userq_post_reset(struct amdgpu_device *adev, bool vram_lost); void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue); void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell); +/* + * CP packs the per-process doorbell_id of the queue in + * CTXID0[9:0] on priv-fault (same encoding KFD uses via + * KFD_CTXID0_DOORBELL_ID_MASK) + */ +#define AMDGPU_CTXID0_DOORBELL_ID_MASK 0x3ff + +void amdgpu_userq_process_reset_irq(struct amdgpu_device *adev, + u32 pasid, u32 doorbell_offset); + int amdgpu_userq_input_va_validate(struct amdgpu_device *adev, struct amdgpu_usermode_queue *queue, u64 addr, u64 expected_size, u64 *va_out); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c index f74ad378e407..7e80442ec3e5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c @@ -30,7 +30,7 @@ #include #include "amdgpu.h" -#include "amdgpu_userq_fence.h" +#include "amdgpu_trace.h" #define AMDGPU_USERQ_MAX_HANDLES (1U << 16) @@ -528,6 +528,8 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data, /* Create the new fence */ amdgpu_userq_fence_init(queue, fence, wptr); + trace_amdgpu_userq_emit_fence(dev->dev, queue, fence); + mutex_unlock(&userq_mgr->userq_mutex); /* @@ -701,7 +703,7 @@ amdgpu_userq_wait_add_fence(struct drm_amdgpu_userq_wait *wait_info, } static int -amdgpu_userq_wait_return_fence_info(struct drm_file *filp, +amdgpu_userq_wait_return_fence_info(struct drm_device *dev, struct drm_file *filp, struct drm_amdgpu_userq_wait *wait_info, u32 *syncobj_handles, u64 *timeline_points, u32 *timeline_handles, @@ -869,6 +871,8 @@ amdgpu_userq_wait_return_fence_info(struct drm_file *filp, amdgpu_userq_fence_driver_get(fence_drv); + trace_amdgpu_userq_wait_deps(dev->dev, waitq, userq_fence); + /* Store drm syncobj's gpu va address and value */ fence_info[cnt].va = fence_drv->va; fence_info[cnt].value = fences[i]->seqno; @@ -969,7 +973,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data, gobj_write, gobj_read); } else { - r = amdgpu_userq_wait_return_fence_info(filp, wait_info, + r = amdgpu_userq_wait_return_fence_info(dev, filp, wait_info, syncobj_handles, timeline_points, timeline_handles, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 480bf88def46..23383ac5323f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -655,6 +655,14 @@ static int amdgpu_uvd_cs_msg_decode(struct amdgpu_device *adev, uint32_t *msg, unsigned int image_size, tmp, min_dpb_size, num_dpb_buffer; unsigned int min_ctx_size = ~0; + /* Reject invalid dimensions to prevent division by zero */ + if (width < 16 || height < 16) { + dev_WARN_ONCE(adev->dev, 1, + "Invalid UVD decoding dimensions (%dx%d)!\n", + width, height); + return -EINVAL; + } + image_size = width * height; image_size += image_size / 2; image_size = ALIGN(image_size, 1024); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index efdebd9c0a1f..eef3c9853a5c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -877,9 +877,20 @@ int amdgpu_vce_ring_parse_cs(struct amdgpu_cs_parser *p, goto out; } - *size = amdgpu_ib_get_value(ib, idx + 8) * - amdgpu_ib_get_value(ib, idx + 10) * - 8 * 3 / 2; + uint32_t width, height; + width = amdgpu_ib_get_value(ib, idx + 8); + height = amdgpu_ib_get_value(ib, idx + 10); + + if (width == 0 || height == 0 || + width > 4096 || height > 2304) { + DRM_ERROR("invalid VCE image size: %ux%u\n", + width, height); + r = -EINVAL; + goto out; + } + + *size = width * height * 8 * 3 / 2; + break; case 0x04000001: /* config extension */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c index 616967519869..fe504f1a3fc8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.c @@ -506,9 +506,8 @@ void amdgpu_vcn_ring_begin_use(struct amdgpu_ring *ring) struct amdgpu_device *adev = ring->adev; struct amdgpu_vcn_inst *vcn_inst = &adev->vcn.inst[ring->me]; - atomic_inc(&vcn_inst->total_submission_cnt); - - cancel_delayed_work_sync(&vcn_inst->idle_work); + if (!atomic_fetch_inc(&vcn_inst->total_submission_cnt)) + cancel_delayed_work_sync(&vcn_inst->idle_work); mutex_lock(&vcn_inst->vcn_pg_lock); vcn_inst->set_pg_state(vcn_inst, AMD_PG_STATE_UNGATE); @@ -550,10 +549,9 @@ void amdgpu_vcn_ring_end_use(struct amdgpu_ring *ring) !adev->vcn.inst[ring->me].using_unified_queue) atomic_dec(&ring->adev->vcn.inst[ring->me].dpg_enc_submission_cnt); - atomic_dec(&ring->adev->vcn.inst[ring->me].total_submission_cnt); - - schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work, - VCN_IDLE_TIMEOUT); + if (atomic_dec_and_test(&ring->adev->vcn.inst[ring->me].total_submission_cnt)) + schedule_delayed_work(&ring->adev->vcn.inst[ring->me].idle_work, + VCN_IDLE_TIMEOUT); } int amdgpu_vcn_dec_ring_test_ring(struct amdgpu_ring *ring) @@ -1485,6 +1483,37 @@ int vcn_set_powergating_state(struct amdgpu_ip_block *ip_block, return ret; } +static struct amdgpu_fence * +amdgpu_vcn_ring_reset_begin_helper(struct amdgpu_ring *ring, + struct amdgpu_ring *guilty_ring, + struct amdgpu_fence *timedout_fence) +{ + struct amdgpu_fence *fence; + + drm_sched_wqueue_stop(&ring->sched); + if (ring == guilty_ring) + fence = timedout_fence; + else + fence = amdgpu_ring_find_guilty_fence(ring); + amdgpu_ring_reset_helper_begin(ring, fence); + + return fence; +} + +static int +amdgpu_vcn_ring_reset_end_helper(struct amdgpu_ring *ring, + struct amdgpu_fence *fence) +{ + int r; + + r = amdgpu_ring_reset_helper_end(ring, fence); + if (r) + return r; + + drm_sched_wqueue_start(&ring->sched); + return 0; +} + /** * amdgpu_vcn_ring_reset - Reset a VCN ring * @ring: ring to reset @@ -1502,48 +1531,33 @@ int amdgpu_vcn_ring_reset(struct amdgpu_ring *ring, { struct amdgpu_device *adev = ring->adev; struct amdgpu_vcn_inst *vinst = &adev->vcn.inst[ring->me]; + struct amdgpu_fence *dec_fence; + struct amdgpu_fence *enc_fence[AMDGPU_VCN_MAX_ENC_RINGS]; int r, i; if (adev->vcn.inst[ring->me].using_unified_queue) return -EINVAL; mutex_lock(&vinst->engine_reset_mutex); - /* Stop the scheduler's work queue for the dec and enc rings if they are running. - * This ensures that no new tasks are submitted to the queues while - * the reset is in progress. - */ - drm_sched_wqueue_stop(&vinst->ring_dec.sched); + dec_fence = amdgpu_vcn_ring_reset_begin_helper(&vinst->ring_dec, ring, + timedout_fence); for (i = 0; i < vinst->num_enc_rings; i++) - drm_sched_wqueue_stop(&vinst->ring_enc[i].sched); + enc_fence[i] = amdgpu_vcn_ring_reset_begin_helper(&vinst->ring_enc[i], ring, + timedout_fence); /* Perform the VCN reset for the specified instance */ r = vinst->reset(vinst); if (r) goto unlock; - r = amdgpu_ring_test_ring(&vinst->ring_dec); + + r = amdgpu_vcn_ring_reset_end_helper(&vinst->ring_dec, dec_fence); if (r) goto unlock; for (i = 0; i < vinst->num_enc_rings; i++) { - r = amdgpu_ring_test_ring(&vinst->ring_enc[i]); + r = amdgpu_vcn_ring_reset_end_helper(&vinst->ring_enc[i], enc_fence[i]); if (r) goto unlock; } - amdgpu_fence_driver_force_completion(&vinst->ring_dec, - (&vinst->ring_dec == ring) ? - &timedout_fence->base : NULL); - for (i = 0; i < vinst->num_enc_rings; i++) - amdgpu_fence_driver_force_completion(&vinst->ring_enc[i], - (&vinst->ring_enc[i] == ring) ? - &timedout_fence->base : NULL); - - /* Restart the scheduler's work queue for the dec and enc rings - * if they were stopped by this function. This allows new tasks - * to be submitted to the queues after the reset is complete. - */ - drm_sched_wqueue_start(&vinst->ring_dec.sched); - for (i = 0; i < vinst->num_enc_rings; i++) - drm_sched_wqueue_start(&vinst->ring_enc[i].sched); - unlock: mutex_unlock(&vinst->engine_reset_mutex); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h index 82624b44e661..bea95307fd42 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.h @@ -368,6 +368,9 @@ struct amdgpu_vcn { struct mutex workload_profile_mutex; u32 reg_count; const struct amdgpu_hwip_reg_entry *reg_list; + + bool disable_uq; + bool disable_kq; }; struct amdgpu_fw_shared_rb_ptrs_struct { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index fee4c94c2585..f317f888b59f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -142,7 +142,7 @@ static void amdgpu_vm_assert_locked(struct amdgpu_vm *vm) static void amdgpu_vm_bo_status_init(struct amdgpu_vm_bo_status *lists) { INIT_LIST_HEAD(&lists->evicted); - INIT_LIST_HEAD(&lists->moved); + INIT_LIST_HEAD(&lists->needs_update); INIT_LIST_HEAD(&lists->idle); } @@ -211,14 +211,14 @@ static void amdgpu_vm_bo_evicted(struct amdgpu_vm_bo_base *vm_bo) amdgpu_vm_bo_unlock_lists(vm_bo); } /** - * amdgpu_vm_bo_moved - vm_bo is moved + * amdgpu_vm_bo_needs_update - vm_bo needs pagetable update * - * @vm_bo: vm_bo which is moved + * @vm_bo: vm_bo which is out of date * - * State for vm_bo objects meaning the underlying BO was moved but the new - * location not yet reflected in the page tables. + * State for vm_bo objects meaning the underlying BO had mapping changes (move, PRT bind/unbind) + * but the new location is not yet reflected in the page tables. */ -static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo) +static void amdgpu_vm_bo_needs_update(struct amdgpu_vm_bo_base *vm_bo) { struct amdgpu_vm_bo_status *lists; struct amdgpu_bo *bo = vm_bo->bo; @@ -232,8 +232,7 @@ static void amdgpu_vm_bo_moved(struct amdgpu_vm_bo_base *vm_bo) vm_bo->moved = false; list_move(&vm_bo->vm_status, &lists->idle); } else { - vm_bo->moved = true; - list_move(&vm_bo->vm_status, &lists->moved); + list_move(&vm_bo->vm_status, &lists->needs_update); } amdgpu_vm_bo_unlock_lists(vm_bo); } @@ -274,14 +273,14 @@ static void amdgpu_vm_bo_reset_state_machine(struct amdgpu_vm *vm) */ amdgpu_vm_assert_locked(vm); list_for_each_entry_safe(vm_bo, tmp, &vm->kernel.idle, vm_status) - amdgpu_vm_bo_moved(vm_bo); + amdgpu_vm_bo_needs_update(vm_bo); list_for_each_entry_safe(vm_bo, tmp, &vm->always_valid.idle, vm_status) - amdgpu_vm_bo_moved(vm_bo); + amdgpu_vm_bo_needs_update(vm_bo); spin_lock(&vm->individual_lock); list_for_each_entry_safe(vm_bo, tmp, &vm->individual.idle, vm_status) { vm_bo->moved = true; - list_move(&vm_bo->vm_status, &vm->individual.moved); + list_move(&vm_bo->vm_status, &vm->individual.needs_update); } spin_unlock(&vm->individual_lock); } @@ -436,7 +435,7 @@ void amdgpu_vm_bo_base_init(struct amdgpu_vm_bo_base *base, */ if (bo->preferred_domains & amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type)) - amdgpu_vm_bo_moved(base); + amdgpu_vm_bo_needs_update(base); else amdgpu_vm_bo_evicted(base); } @@ -608,7 +607,8 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, return r; vm->update_funcs->map_table(to_amdgpu_bo_vm(bo_base->bo)); - amdgpu_vm_bo_moved(bo_base); + bo_base->moved = true; + amdgpu_vm_bo_needs_update(bo_base); } /* @@ -625,7 +625,8 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, if (r) return r; - amdgpu_vm_bo_moved(bo_base); + bo_base->moved = true; + amdgpu_vm_bo_needs_update(bo_base); } if (!ticket) @@ -645,7 +646,8 @@ int amdgpu_vm_validate(struct amdgpu_device *adev, struct amdgpu_vm *vm, if (r) return r; - amdgpu_vm_bo_moved(bo_base); + bo_base->moved = true; + amdgpu_vm_bo_needs_update(bo_base); /* It's a bit inefficient to always jump back to the start, but * we would need to re-structure the KFD for properly fixing @@ -979,7 +981,7 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, amdgpu_vm_assert_locked(vm); - if (list_empty(&vm->kernel.moved)) + if (list_empty(&vm->kernel.needs_update)) return 0; if (!drm_dev_enter(adev_to_drm(adev), &idx)) @@ -995,7 +997,7 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, if (r) goto error; - list_for_each_entry(entry, &vm->kernel.moved, vm_status) { + list_for_each_entry(entry, &vm->kernel.needs_update, vm_status) { /* vm_flush_needed after updating moved PDEs */ flush_tlb_needed |= entry->moved; @@ -1011,7 +1013,8 @@ int amdgpu_vm_update_pdes(struct amdgpu_device *adev, if (flush_tlb_needed) atomic64_inc(&vm->tlb_seq); - list_for_each_entry_safe(entry, tmp, &vm->kernel.moved, vm_status) + list_for_each_entry_safe(entry, tmp, &vm->kernel.needs_update, + vm_status) amdgpu_vm_bo_idle(entry); error: @@ -1615,7 +1618,7 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, bool clear, unlock; int r; - list_for_each_entry_safe(bo_va, tmp, &vm->always_valid.moved, + list_for_each_entry_safe(bo_va, tmp, &vm->always_valid.needs_update, base.vm_status) { /* Per VM BOs never need to bo cleared in the page tables */ r = amdgpu_vm_bo_update(adev, bo_va, false); @@ -1624,8 +1627,8 @@ int amdgpu_vm_handle_moved(struct amdgpu_device *adev, } spin_lock(&vm->individual_lock); - while (!list_empty(&vm->individual.moved)) { - bo_va = list_first_entry(&vm->individual.moved, + while (!list_empty(&vm->individual.needs_update)) { + bo_va = list_first_entry(&vm->individual.needs_update, typeof(*bo_va), base.vm_status); bo = bo_va->base.bo; resv = bo->tbo.base.resv; @@ -1786,7 +1789,7 @@ static void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev, amdgpu_vm_prt_get(adev); if (amdgpu_vm_is_bo_always_valid(vm, bo) && !bo_va->base.moved) - amdgpu_vm_bo_moved(&bo_va->base); + amdgpu_vm_bo_needs_update(&bo_va->base); trace_amdgpu_vm_bo_map(bo_va, mapping); } @@ -2095,7 +2098,7 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, if (amdgpu_vm_is_bo_always_valid(vm, bo) && !before->bo_va->base.moved) - amdgpu_vm_bo_moved(&before->bo_va->base); + amdgpu_vm_bo_needs_update(&before->bo_va->base); } else { kfree(before); } @@ -2110,7 +2113,7 @@ int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev, if (amdgpu_vm_is_bo_always_valid(vm, bo) && !after->bo_va->base.moved) - amdgpu_vm_bo_moved(&after->bo_va->base); + amdgpu_vm_bo_needs_update(&after->bo_va->base); } else { kfree(after); } @@ -2284,7 +2287,8 @@ void amdgpu_vm_bo_invalidate(struct amdgpu_bo *bo, bool evicted) if (bo_base->moved) continue; - amdgpu_vm_bo_moved(bo_base); + bo_base->moved = true; + amdgpu_vm_bo_needs_update(bo_base); } } @@ -3098,7 +3102,7 @@ static void amdgpu_debugfs_vm_bo_status_info(struct seq_file *m, id = 0; seq_puts(m, "\tMoved BOs:\n"); - list_for_each_entry(base, &lists->moved, vm_status) { + list_for_each_entry(base, &lists->needs_update, vm_status) { if (!base->bo) continue; @@ -3107,7 +3111,7 @@ static void amdgpu_debugfs_vm_bo_status_info(struct seq_file *m, id = 0; seq_puts(m, "\tIdle BOs:\n"); - list_for_each_entry(base, &lists->moved, vm_status) { + list_for_each_entry(base, &lists->needs_update, vm_status) { if (!base->bo) continue; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index b32f51a78cd8..5822836fa4a3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -212,7 +212,8 @@ struct amdgpu_vm_bo_base { * protected by vm BO being reserved */ bool shared; - /* protected by the BO being reserved */ + /* if the BO was moved and all mappings are invalid + * protected by the BO being reserved */ bool moved; }; @@ -220,14 +221,14 @@ struct amdgpu_vm_bo_base { * The following status lists contain amdgpu_vm_bo_base objects for * either PD/PTs, per VM BOs or BOs with individual resv object. * - * The state transits are: evicted -> moved -> idle + * The state transits are: evicted -> needs_update -> idle */ struct amdgpu_vm_bo_status { /* BOs evicted which need to move into place again */ struct list_head evicted; - /* BOs which moved but new location hasn't been updated in the PDs/PTs */ - struct list_head moved; + /* BOs whose mappings changed but PDs/PTs haven't been updated */ + struct list_head needs_update; /* BOs done with the state machine and need no further action */ struct list_head idle; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c index 409e103ffe8c..35faea0ff17f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c @@ -381,7 +381,8 @@ int amdgpu_xcp_get_inst_details(struct amdgpu_xcp *xcp, enum AMDGPU_XCP_IP_BLOCK ip, uint32_t *inst_mask) { - if (!xcp->valid || !inst_mask || !(xcp->ip[ip].valid)) + if (!xcp->valid || !inst_mask || ip >= AMDGPU_XCP_MAX_BLOCKS || + !(xcp->ip[ip].valid)) return -EINVAL; *inst_mask = xcp->ip[ip].inst_mask; @@ -468,14 +469,18 @@ void amdgpu_xcp_release_sched(struct amdgpu_device *adev, { struct drm_gpu_scheduler *sched = container_of(entity->entity.rq, typeof(*sched), rq); + struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr; - if (!adev->xcp_mgr) + if (!xcp_mgr) return; if (drm_sched_wqueue_ready(sched)) { struct amdgpu_ring *ring = to_amdgpu_ring(sched); - atomic_dec(&adev->xcp_mgr->xcp[ring->xcp_id].ref_cnt); + mutex_lock(&xcp_mgr->xcp_lock); + if (ring->xcp_id < xcp_mgr->num_xcps && xcp_mgr->xcp[ring->xcp_id].valid) + atomic_dec(&xcp_mgr->xcp[ring->xcp_id].ref_cnt); + mutex_unlock(&xcp_mgr->xcp_lock); } } @@ -488,7 +493,9 @@ int amdgpu_xcp_select_scheds(struct amdgpu_device *adev, u32 sel_xcp_id; int i; struct amdgpu_xcp_mgr *xcp_mgr = adev->xcp_mgr; + int r = 0; + mutex_lock(&xcp_mgr->xcp_lock); if (fpriv->xcp_id == AMDGPU_XCP_NO_PARTITION) { u32 least_ref_cnt = ~0; @@ -505,19 +512,27 @@ int amdgpu_xcp_select_scheds(struct amdgpu_device *adev, } sel_xcp_id = fpriv->xcp_id; + if (sel_xcp_id >= xcp_mgr->num_xcps || !xcp_mgr->xcp[sel_xcp_id].valid) { + dev_err(adev->dev, "Selected partition #%d is not valid.", sel_xcp_id); + r = -ENODEV; + goto out; + } + if (xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds) { *num_scheds = - xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds; + xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].num_scheds; *scheds = - xcp_mgr->xcp[fpriv->xcp_id].gpu_sched[hw_ip][hw_prio].sched; - atomic_inc(&adev->xcp_mgr->xcp[sel_xcp_id].ref_cnt); + xcp_mgr->xcp[sel_xcp_id].gpu_sched[hw_ip][hw_prio].sched; + atomic_inc(&xcp_mgr->xcp[sel_xcp_id].ref_cnt); dev_dbg(adev->dev, "Selected partition #%d", sel_xcp_id); } else { dev_err(adev->dev, "Failed to schedule partition #%d.", sel_xcp_id); - return -ENOENT; + r = -ENOENT; } - return 0; +out: + mutex_unlock(&xcp_mgr->xcp_lock); + return r; } static void amdgpu_set_xcp_id(struct amdgpu_device *adev, @@ -574,6 +589,9 @@ static void amdgpu_xcp_gpu_sched_update(struct amdgpu_device *adev, { unsigned int *num_gpu_sched; + if (sel_xcp_id >= MAX_XCP || sel_xcp_id == AMDGPU_XCP_NO_PARTITION) + return; + num_gpu_sched = &adev->xcp_mgr->xcp[sel_xcp_id] .gpu_sched[ring->funcs->type][ring->hw_prio].num_scheds; adev->xcp_mgr->xcp[sel_xcp_id].gpu_sched[ring->funcs->type][ring->hw_prio] @@ -903,7 +921,7 @@ static void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev) { struct amdgpu_xcp_res_details *xcp_res; struct amdgpu_xcp_cfg *xcp_cfg; - int i, r, j, rid, mode; + int i, r, rid, mode; if (!adev->xcp_mgr) return; @@ -949,14 +967,16 @@ static void amdgpu_xcp_cfg_sysfs_init(struct amdgpu_device *adev) &xcp_cfg_res_sysfs_ktype, &xcp_cfg->kobj, "%s", xcp_res_names[rid]); - if (r) + if (r) { + kobject_put(&xcp_res->kobj); goto err; + } } adev->xcp_mgr->xcp_cfg = xcp_cfg; return; err: - for (j = 0; j < i; j++) { + while (i--) { xcp_res = &xcp_cfg->xcp_res[i]; kobject_put(&xcp_res->kobj); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c index e63d05c477a0..d2c5bb50d94a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_xgmi.c @@ -106,53 +106,6 @@ static const int walf_pcs_err_noncorrectable_mask_reg_aldebaran[] = { smnPCS_GOPX1_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000 }; -static const int xgmi3x16_pcs_err_status_reg_v6_4[] = { - smnPCS_XGMI3X16_PCS_ERROR_STATUS, - smnPCS_XGMI3X16_PCS_ERROR_STATUS + 0x100000 -}; - -static const int xgmi3x16_pcs_err_noncorrectable_mask_reg_v6_4[] = { - smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK, - smnPCS_XGMI3X16_PCS_ERROR_NONCORRECTABLE_MASK + 0x100000 -}; - -static const u64 xgmi_v6_4_0_mca_base_array[] = { - 0x11a09200, - 0x11b09200, -}; - -static const char *xgmi_v6_4_0_ras_error_code_ext[32] = { - [0x00] = "XGMI PCS DataLossErr", - [0x01] = "XGMI PCS TrainingErr", - [0x02] = "XGMI PCS FlowCtrlAckErr", - [0x03] = "XGMI PCS RxFifoUnderflowErr", - [0x04] = "XGMI PCS RxFifoOverflowErr", - [0x05] = "XGMI PCS CRCErr", - [0x06] = "XGMI PCS BERExceededErr", - [0x07] = "XGMI PCS TxMetaDataErr", - [0x08] = "XGMI PCS ReplayBufParityErr", - [0x09] = "XGMI PCS DataParityErr", - [0x0a] = "XGMI PCS ReplayFifoOverflowErr", - [0x0b] = "XGMI PCS ReplayFifoUnderflowErr", - [0x0c] = "XGMI PCS ElasticFifoOverflowErr", - [0x0d] = "XGMI PCS DeskewErr", - [0x0e] = "XGMI PCS FlowCtrlCRCErr", - [0x0f] = "XGMI PCS DataStartupLimitErr", - [0x10] = "XGMI PCS FCInitTimeoutErr", - [0x11] = "XGMI PCS RecoveryTimeoutErr", - [0x12] = "XGMI PCS ReadySerialTimeoutErr", - [0x13] = "XGMI PCS ReadySerialAttemptErr", - [0x14] = "XGMI PCS RecoveryAttemptErr", - [0x15] = "XGMI PCS RecoveryRelockAttemptErr", - [0x16] = "XGMI PCS ReplayAttemptErr", - [0x17] = "XGMI PCS SyncHdrErr", - [0x18] = "XGMI PCS TxReplayTimeoutErr", - [0x19] = "XGMI PCS RxReplayTimeoutErr", - [0x1a] = "XGMI PCS LinkSubTxTimeoutErr", - [0x1b] = "XGMI PCS LinkSubRxTimeoutErr", - [0x1c] = "XGMI PCS RxCMDPktErr", -}; - static const struct amdgpu_pcs_ras_field xgmi_pcs_ras_fields[] = { {"XGMI PCS DataLossErr", SOC15_REG_FIELD(XGMI0_PCS_GOPX16_PCS_ERROR_STATUS, DataLossErr)}, @@ -1152,91 +1105,15 @@ int amdgpu_xgmi_remove_device(struct amdgpu_device *adev) return 0; } -static int xgmi_v6_4_0_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct amdgpu_device *adev = handle->adev; - struct aca_bank_info info; - const char *error_str; - u64 status, count; - int ret, ext_error_code; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - status = bank->regs[ACA_REG_IDX_STATUS]; - ext_error_code = ACA_REG__STATUS__ERRORCODEEXT(status); - - error_str = ext_error_code < ARRAY_SIZE(xgmi_v6_4_0_ras_error_code_ext) ? - xgmi_v6_4_0_ras_error_code_ext[ext_error_code] : NULL; - if (error_str) - dev_info(adev->dev, "%s detected\n", error_str); - - count = ACA_REG__MISC0__ERRCNT(bank->regs[ACA_REG_IDX_MISC0]); - - switch (type) { - case ACA_SMU_TYPE_UE: - if (ext_error_code != 0 && ext_error_code != 1 && ext_error_code != 9) - count = 0ULL; - - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, count); - break; - case ACA_SMU_TYPE_CE: - count = ext_error_code == 6 ? count : 0ULL; - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, count); - break; - default: - return -EINVAL; - } - - return ret; -} - -static const struct aca_bank_ops xgmi_v6_4_0_aca_bank_ops = { - .aca_bank_parser = xgmi_v6_4_0_aca_bank_parser, -}; - -static const struct aca_info xgmi_v6_4_0_aca_info = { - .hwip = ACA_HWIP_TYPE_PCS_XGMI, - .mask = ACA_ERROR_UE_MASK | ACA_ERROR_CE_MASK, - .bank_ops = &xgmi_v6_4_0_aca_bank_ops, -}; - static int amdgpu_xgmi_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) { - int r; - if (!adev->gmc.xgmi.supported || adev->gmc.xgmi.num_physical_nodes == 0) return 0; amdgpu_ras_reset_error_count(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL); - r = amdgpu_ras_block_late_init(adev, ras_block); - if (r) - return r; - - switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { - case IP_VERSION(6, 4, 0): - case IP_VERSION(6, 4, 1): - r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__XGMI_WAFL, - &xgmi_v6_4_0_aca_info, NULL); - if (r) - goto late_fini; - break; - default: - break; - } - - return 0; - -late_fini: - amdgpu_ras_block_late_fini(adev, ras_block); - - return r; + return amdgpu_ras_block_late_init(adev, ras_block); } uint64_t amdgpu_xgmi_get_relative_phy_addr(struct amdgpu_device *adev, @@ -1252,7 +1129,7 @@ static void pcs_clear_status(struct amdgpu_device *adev, uint32_t pcs_status_reg WREG32_PCIE(pcs_status_reg, 0); } -static void amdgpu_xgmi_legacy_reset_ras_error_count(struct amdgpu_device *adev) +static void amdgpu_xgmi_reset_ras_error_count(struct amdgpu_device *adev) { uint32_t i; @@ -1278,54 +1155,6 @@ static void amdgpu_xgmi_legacy_reset_ras_error_count(struct amdgpu_device *adev) default: break; } - - switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { - case IP_VERSION(6, 4, 0): - case IP_VERSION(6, 4, 1): - for (i = 0; i < ARRAY_SIZE(xgmi3x16_pcs_err_status_reg_v6_4); i++) - pcs_clear_status(adev, - xgmi3x16_pcs_err_status_reg_v6_4[i]); - break; - default: - break; - } -} - -static void __xgmi_v6_4_0_reset_error_count(struct amdgpu_device *adev, int xgmi_inst, u64 mca_base) -{ - uint64_t smn_base = - amdgpu_reg_get_smn_base64(adev, XGMI_HWIP, xgmi_inst); - - WREG64_MCA(smn_base, mca_base, ACA_REG_IDX_STATUS, 0ULL); -} - -static void xgmi_v6_4_0_reset_error_count(struct amdgpu_device *adev, int xgmi_inst) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(xgmi_v6_4_0_mca_base_array); i++) - __xgmi_v6_4_0_reset_error_count(adev, xgmi_inst, xgmi_v6_4_0_mca_base_array[i]); -} - -static void xgmi_v6_4_0_reset_ras_error_count(struct amdgpu_device *adev) -{ - int i; - - for_each_inst(i, adev->aid_mask) - xgmi_v6_4_0_reset_error_count(adev, i); -} - -static void amdgpu_xgmi_reset_ras_error_count(struct amdgpu_device *adev) -{ - switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { - case IP_VERSION(6, 4, 0): - case IP_VERSION(6, 4, 1): - xgmi_v6_4_0_reset_ras_error_count(adev); - break; - default: - amdgpu_xgmi_legacy_reset_ras_error_count(adev); - break; - } } static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev, @@ -1343,11 +1172,7 @@ static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev, if (is_xgmi_pcs) { if (amdgpu_ip_version(adev, XGMI_HWIP, 0) == - IP_VERSION(6, 1, 0) || - amdgpu_ip_version(adev, XGMI_HWIP, 0) == - IP_VERSION(6, 4, 0) || - amdgpu_ip_version(adev, XGMI_HWIP, 0) == - IP_VERSION(6, 4, 1)) { + IP_VERSION(6, 1, 0)) { pcs_ras_fields = &xgmi3x16_pcs_ras_fields[0]; field_array_size = ARRAY_SIZE(xgmi3x16_pcs_ras_fields); } else { @@ -1381,11 +1206,11 @@ static int amdgpu_xgmi_query_pcs_error_status(struct amdgpu_device *adev, return 0; } -static void amdgpu_xgmi_legacy_query_ras_error_count(struct amdgpu_device *adev, +static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) { struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - int i, supported = 1; + int i; uint32_t data, mask_data = 0; uint32_t ue_cnt = 0, ce_cnt = 0; @@ -1449,26 +1274,6 @@ static void amdgpu_xgmi_legacy_query_ras_error_count(struct amdgpu_device *adev, } break; default: - supported = 0; - break; - } - - switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { - case IP_VERSION(6, 4, 0): - case IP_VERSION(6, 4, 1): - /* check xgmi3x16 pcs error */ - for (i = 0; i < ARRAY_SIZE(xgmi3x16_pcs_err_status_reg_v6_4); i++) { - data = RREG32_PCIE(xgmi3x16_pcs_err_status_reg_v6_4[i]); - mask_data = - RREG32_PCIE(xgmi3x16_pcs_err_noncorrectable_mask_reg_v6_4[i]); - if (data) - amdgpu_xgmi_query_pcs_error_status(adev, data, - mask_data, &ue_cnt, &ce_cnt, true, true); - } - break; - default: - if (!supported) - dev_warn(adev->dev, "XGMI RAS error query not supported"); break; } @@ -1478,90 +1283,6 @@ static void amdgpu_xgmi_legacy_query_ras_error_count(struct amdgpu_device *adev, err_data->ce_count += ce_cnt; } -static enum aca_error_type xgmi_v6_4_0_pcs_mca_get_error_type(struct amdgpu_device *adev, u64 status) -{ - const char *error_str; - int ext_error_code; - - ext_error_code = ACA_REG__STATUS__ERRORCODEEXT(status); - - error_str = ext_error_code < ARRAY_SIZE(xgmi_v6_4_0_ras_error_code_ext) ? - xgmi_v6_4_0_ras_error_code_ext[ext_error_code] : NULL; - if (error_str) - dev_info(adev->dev, "%s detected\n", error_str); - - switch (ext_error_code) { - case 0: - return ACA_ERROR_TYPE_UE; - case 6: - return ACA_ERROR_TYPE_CE; - default: - return -EINVAL; - } - - return -EINVAL; -} - -static void __xgmi_v6_4_0_query_error_count(struct amdgpu_device *adev, struct amdgpu_smuio_mcm_config_info *mcm_info, - u64 mca_base, struct ras_err_data *err_data) -{ - int xgmi_inst = mcm_info->die_id; - uint64_t smn_base; - u64 status = 0; - - status = RREG64_MCA(xgmi_inst, mca_base, ACA_REG_IDX_STATUS); - if (!ACA_REG__STATUS__VAL(status)) - return; - - switch (xgmi_v6_4_0_pcs_mca_get_error_type(adev, status)) { - case ACA_ERROR_TYPE_UE: - amdgpu_ras_error_statistic_ue_count(err_data, mcm_info, 1ULL); - break; - case ACA_ERROR_TYPE_CE: - amdgpu_ras_error_statistic_ce_count(err_data, mcm_info, 1ULL); - break; - default: - break; - } - smn_base = amdgpu_reg_get_smn_base64(adev, XGMI_HWIP, xgmi_inst); - WREG64_MCA(smn_base, mca_base, ACA_REG_IDX_STATUS, 0ULL); -} - -static void xgmi_v6_4_0_query_error_count(struct amdgpu_device *adev, int xgmi_inst, struct ras_err_data *err_data) -{ - struct amdgpu_smuio_mcm_config_info mcm_info = { - .socket_id = adev->smuio.funcs->get_socket_id(adev), - .die_id = xgmi_inst, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(xgmi_v6_4_0_mca_base_array); i++) - __xgmi_v6_4_0_query_error_count(adev, &mcm_info, xgmi_v6_4_0_mca_base_array[i], err_data); -} - -static void xgmi_v6_4_0_query_ras_error_count(struct amdgpu_device *adev, void *ras_error_status) -{ - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - int i; - - for_each_inst(i, adev->aid_mask) - xgmi_v6_4_0_query_error_count(adev, i, err_data); -} - -static void amdgpu_xgmi_query_ras_error_count(struct amdgpu_device *adev, - void *ras_error_status) -{ - switch (amdgpu_ip_version(adev, XGMI_HWIP, 0)) { - case IP_VERSION(6, 4, 0): - case IP_VERSION(6, 4, 1): - xgmi_v6_4_0_query_ras_error_count(adev, ras_error_status); - break; - default: - amdgpu_xgmi_legacy_query_ras_error_count(adev, ras_error_status); - break; - } -} - /* Trigger XGMI/WAFL error */ static int amdgpu_ras_error_inject_xgmi(struct amdgpu_device *adev, void *inject_if, uint32_t instance_mask) @@ -1663,6 +1384,16 @@ static void amdgpu_xgmi_reset_on_init_work(struct work_struct *work) if (r && r != -EHWPOISON) dev_err(tmp_adev->dev, "error during bad page data initialization"); + + /* + * For the reset-on-init path (e.g. an NPS memory partition + * switch) the RAS IP block hw_init was skipped under the + * minimal init level, so uniras was never enabled. Bring it + * up now that the reset domain has been unlocked. This is a + * no-op for any other reset path where RAS is already + * initialized, and for non-uniras devices. + */ + amdgpu_ras_resume_after_reset(tmp_adev); } } diff --git a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c index 72ea37dbfea8..cddfe4015f53 100644 --- a/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c +++ b/drivers/gpu/drm/amd/amdgpu/aqua_vanjaram.c @@ -273,8 +273,10 @@ static int aqua_vanjaram_get_xcp_res_info(struct amdgpu_xcp_mgr *xcp_mgr, xcp_cfg->num_res = ARRAY_SIZE(max_res); for (i = 0; i < xcp_cfg->num_res; i++) { - res_lt_xcp = max_res[i] < num_xcp; xcp_cfg->xcp_res[i].id = i; + if (!max_res[i]) + continue; + res_lt_xcp = max_res[i] < num_xcp; xcp_cfg->xcp_res[i].num_inst = res_lt_xcp ? 1 : max_res[i] / num_xcp; xcp_cfg->xcp_res[i].num_inst = @@ -589,6 +591,29 @@ static struct aqua_reg_list pcie_reg_addrs[] = { { smreg_0x1A380088, 6, DW_ADDR_INCR }, }; +/* + * Return the GPU's internal US switch port, or NULL if it is not visible + * (e.g. passthrough) or the EP is parented under an unrelated bridge. + */ +static struct pci_dev *aqua_vanjaram_get_us_pdev(struct amdgpu_device *adev) +{ + struct pci_dev *ds_pdev, *us_pdev; + + ds_pdev = pci_upstream_bridge(adev->pdev); + if (!ds_pdev || ds_pdev->vendor != PCI_VENDOR_ID_ATI || + pci_pcie_type(ds_pdev) != PCI_EXP_TYPE_DOWNSTREAM) + return NULL; + + us_pdev = pci_upstream_bridge(ds_pdev); + if (!us_pdev || + (us_pdev->vendor != PCI_VENDOR_ID_ATI && + us_pdev->vendor != PCI_VENDOR_ID_AMD) || + pci_pcie_type(us_pdev) != PCI_EXP_TYPE_UPSTREAM) + return NULL; + + return us_pdev; +} + static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev, void *buf, size_t max_size) { @@ -596,7 +621,7 @@ static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev, uint32_t start_addr, incrx, num_regs, szbuf; struct amdgpu_regs_pcie_v1_0 *pcie_regs; struct amdgpu_smn_reg_data *reg_data; - struct pci_dev *us_pdev, *ds_pdev; + struct pci_dev *us_pdev; int aer_cap, r, n; if (!buf || !max_size) @@ -628,25 +653,27 @@ static ssize_t aqua_vanjaram_read_pcie_state(struct amdgpu_device *adev, } } - ds_pdev = pci_upstream_bridge(adev->pdev); - us_pdev = pci_upstream_bridge(ds_pdev); + us_pdev = aqua_vanjaram_get_us_pdev(adev); + if (us_pdev) { + pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA, + &pcie_regs->device_status); + pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA, + &pcie_regs->link_status); - pcie_capability_read_word(us_pdev, PCI_EXP_DEVSTA, - &pcie_regs->device_status); - pcie_capability_read_word(us_pdev, PCI_EXP_LNKSTA, - &pcie_regs->link_status); + aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR); + if (aer_cap) { + pci_read_config_dword(us_pdev, + aer_cap + PCI_ERR_COR_STATUS, + &pcie_regs->pcie_corr_err_status); + pci_read_config_dword(us_pdev, + aer_cap + PCI_ERR_UNCOR_STATUS, + &pcie_regs->pcie_uncorr_err_status); + } - aer_cap = pci_find_ext_capability(us_pdev, PCI_EXT_CAP_ID_ERR); - if (aer_cap) { - pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_COR_STATUS, - &pcie_regs->pcie_corr_err_status); - pci_read_config_dword(us_pdev, aer_cap + PCI_ERR_UNCOR_STATUS, - &pcie_regs->pcie_uncorr_err_status); + pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS, + &pcie_regs->sub_bus_number_latency); } - pci_read_config_dword(us_pdev, PCI_PRIMARY_BUS, - &pcie_regs->sub_bus_number_latency); - pcie_reg_state->common_header.structure_size = szbuf; pcie_reg_state->common_header.format_revision = 1; pcie_reg_state->common_header.content_revision = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index ca5d091549e1..e0e585f280e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -114,8 +114,10 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, uint32_t index, uint32_t data) { uint32_t temp = 0xCDCDCDCD; + int start = base; - while (1) + /* IIO opcodes read up to base+3; keep within the BIOS image */ + while (base + 3 < ctx->bios_size) switch (CU8(base)) { case ATOM_IIO_NOP: base++; @@ -180,6 +182,9 @@ static uint32_t atom_iio_execute(struct atom_context *ctx, int base, pr_info("Unknown IIO opcode\n"); return 0; } + + pr_info("IIO method starting at offset %d runs past BIOS image\n", start); + return 0; } static uint32_t atom_get_src_int(atom_exec_context *ctx, uint8_t attr, @@ -1327,11 +1332,25 @@ static void atom_index_iio(struct atom_context *ctx, int base) ctx->iio = kzalloc(2 * 256, GFP_KERNEL); if (!ctx->iio) return; - while (CU8(base) == ATOM_IIO_START) { - ctx->iio[CU8(base + 1)] = base + 2; + while (base + 1 < ctx->bios_size && CU8(base) == ATOM_IIO_START) { + uint8_t index = CU8(base + 1); + int start = base + 2; base += 2; - while (CU8(base) != ATOM_IIO_END) - base += atom_iio_len[CU8(base)]; + while (base < ctx->bios_size && CU8(base) != ATOM_IIO_END) { + uint8_t op = CU8(base); + + /* + * Unknown opcode: its length is unknown so the byte + * stream cannot be resynced reliably. + */ + if (op >= ARRAY_SIZE(atom_iio_len)) + return; + base += atom_iio_len[op]; + } + if (base >= ctx->bios_size) + return; + /* Only index well-formed methods, others stay 0 */ + ctx->iio[index] = start; base += 3; } } @@ -1339,6 +1358,7 @@ static void atom_index_iio(struct atom_context *ctx, int base) static void atom_get_vbios_name(struct atom_context *ctx) { unsigned char *p_rom; + unsigned char *p_end; unsigned char str_num; unsigned short off_to_vbios_str; unsigned char *c_ptr; @@ -1349,39 +1369,48 @@ static void atom_get_vbios_name(struct atom_context *ctx) char *back; p_rom = ctx->bios; + p_end = p_rom + ctx->bios_size; + + if (p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START + 1 >= p_end) + goto no_name; str_num = *(p_rom + OFFSET_TO_GET_ATOMBIOS_NUMBER_OF_STRINGS); - if (str_num != 0) { - off_to_vbios_str = - *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START); + if (!str_num) + goto no_name; - c_ptr = (unsigned char *)(p_rom + off_to_vbios_str); - } else { - /* do not know where to find name */ - memcpy(ctx->name, na, 7); - ctx->name[7] = 0; - return; - } + off_to_vbios_str = + *(unsigned short *)(p_rom + OFFSET_TO_GET_ATOMBIOS_STRING_START); + + c_ptr = (unsigned char *)(p_rom + off_to_vbios_str); + if (c_ptr >= p_end) + goto no_name; /* * skip the atombios strings, usually 4 * 1st is P/N, 2nd is ASIC, 3rd is PCI type, 4th is Memory type */ for (i = 0; i < str_num; i++) { - while (*c_ptr != 0) + while (c_ptr < p_end && *c_ptr != 0) c_ptr++; c_ptr++; } /* skip the following 2 chars: 0x0D 0x0A */ c_ptr += 2; + if (c_ptr >= p_end) + goto no_name; - name_size = strnlen(c_ptr, STRLEN_LONG - 1); + name_size = strnlen(c_ptr, min(STRLEN_LONG - 1, (int)(p_end - c_ptr))); memcpy(ctx->name, c_ptr, name_size); back = ctx->name + name_size; while ((*--back) == ' ') ; *(back + 1) = '\0'; + return; + +no_name: + /* do not know where to find name */ + strscpy(ctx->name, na, sizeof(ctx->name)); } static void atom_get_vbios_date(struct atom_context *ctx) @@ -1553,7 +1582,7 @@ static inline void atom_print_vbios_info(struct atom_context *ctx) drm_info(ctx->card->dev, "ATOM BIOS: %s\n", vbios_info); } -struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios) +struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios, uint32_t bios_size) { int base; struct atom_context *ctx = @@ -1567,6 +1596,7 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios) ctx->card = card; ctx->bios = bios; + ctx->bios_size = bios_size; if (CU16(0) != ATOM_BIOS_MAGIC) { pr_info("Invalid BIOS magic\n"); diff --git a/drivers/gpu/drm/amd/amdgpu/atom.h b/drivers/gpu/drm/amd/amdgpu/atom.h index bb3d9eb7eb6b..4687c019cbe3 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.h +++ b/drivers/gpu/drm/amd/amdgpu/atom.h @@ -133,6 +133,7 @@ struct atom_context { struct card_info *card; struct mutex mutex; void *bios; + uint32_t bios_size; uint32_t cmd_table, data_table; uint16_t *iio; @@ -160,7 +161,7 @@ struct atom_context { extern int amdgpu_atom_debug; -struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios); +struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios, uint32_t bios_size); int amdgpu_atom_execute_table(struct atom_context *ctx, int index, uint32_t *params, int params_size); int amdgpu_atom_asic_init(struct atom_context *ctx); void amdgpu_atom_destroy(struct atom_context *ctx); diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 29954c7d61b0..77e120a72815 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -1876,12 +1876,6 @@ static void cik_invalidate_hdp(struct amdgpu_device *adev, } } -static bool cik_need_full_reset(struct amdgpu_device *adev) -{ - /* change this when we support soft reset */ - return true; -} - static void cik_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0, uint64_t *count1) { @@ -1971,7 +1965,6 @@ static const struct amdgpu_asic_funcs cik_asic_funcs = .get_config_memsize = &cik_get_config_memsize, .flush_hdp = &cik_flush_hdp, .invalidate_hdp = &cik_invalidate_hdp, - .need_full_reset = &cik_need_full_reset, .init_doorbell_index = &legacy_doorbell_index_init, .get_pcie_usage = &cik_get_pcie_usage, .need_reset_on_init = &cik_need_reset_on_init, diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index c8f465158e71..f2977fe6d824 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -410,36 +410,6 @@ static u32 dce_v10_0_hpd_get_gpio_reg(struct amdgpu_device *adev) return mmDC_GPIO_HPD_A; } -static bool dce_v10_0_is_display_hung(struct amdgpu_device *adev) -{ - u32 crtc_hung = 0; - u32 crtc_status[6]; - u32 i, j, tmp; - - for (i = 0; i < adev->mode_info.num_crtc; i++) { - tmp = RREG32(mmCRTC_CONTROL + crtc_offsets[i]); - if (REG_GET_FIELD(tmp, CRTC_CONTROL, CRTC_MASTER_EN)) { - crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); - crtc_hung |= (1 << i); - } - } - - for (j = 0; j < 10; j++) { - for (i = 0; i < adev->mode_info.num_crtc; i++) { - if (crtc_hung & (1 << i)) { - tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); - if (tmp != crtc_status[i]) - crtc_hung &= ~(1 << i); - } - } - if (crtc_hung == 0) - return false; - udelay(100); - } - - return true; -} - static void dce_v10_0_set_vga_render_state(struct amdgpu_device *adev, bool render) { @@ -2956,40 +2926,6 @@ static bool dce_v10_0_is_idle(struct amdgpu_ip_block *ip_block) return true; } -static bool dce_v10_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - return dce_v10_0_is_display_hung(adev); -} - -static int dce_v10_0_soft_reset(struct amdgpu_ip_block *ip_block) -{ - u32 srbm_soft_reset = 0, tmp; - struct amdgpu_device *adev = ip_block->adev; - - if (dce_v10_0_is_display_hung(adev)) - srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; - - if (srbm_soft_reset) { - tmp = RREG32(mmSRBM_SOFT_RESET); - tmp |= srbm_soft_reset; - dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~srbm_soft_reset; - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - /* Wait a little for things to settle down */ - udelay(50); - } - return 0; -} - static void dce_v10_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, int crtc, enum amdgpu_interrupt_state state) @@ -3332,8 +3268,6 @@ static const struct amd_ip_funcs dce_v10_0_ip_funcs = { .suspend = dce_v10_0_suspend, .resume = dce_v10_0_resume, .is_idle = dce_v10_0_is_idle, - .check_soft_reset = dce_v10_0_check_soft_reset, - .soft_reset = dce_v10_0_soft_reset, .set_clockgating_state = dce_v10_0_set_clockgating_state, .set_powergating_state = dce_v10_0_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index 58d0da5c2a74..c68de0fe1d7d 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -378,35 +378,6 @@ static u32 dce_v6_0_hpd_get_gpio_reg(struct amdgpu_device *adev) return mmDC_GPIO_HPD_A; } -static bool dce_v6_0_is_display_hung(struct amdgpu_device *adev) -{ - u32 crtc_hung = 0; - u32 crtc_status[6]; - u32 i, j, tmp; - - for (i = 0; i < adev->mode_info.num_crtc; i++) { - if (RREG32(mmCRTC_CONTROL + crtc_offsets[i]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK) { - crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); - crtc_hung |= (1 << i); - } - } - - for (j = 0; j < 10; j++) { - for (i = 0; i < adev->mode_info.num_crtc; i++) { - if (crtc_hung & (1 << i)) { - tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); - if (tmp != crtc_status[i]) - crtc_hung &= ~(1 << i); - } - } - if (crtc_hung == 0) - return false; - udelay(100); - } - - return true; -} - static void dce_v6_0_set_vga_render_state(struct amdgpu_device *adev, bool render) { @@ -2901,33 +2872,6 @@ static bool dce_v6_0_is_idle(struct amdgpu_ip_block *ip_block) return true; } -static int dce_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) -{ - u32 srbm_soft_reset = 0, tmp; - struct amdgpu_device *adev = ip_block->adev; - - if (dce_v6_0_is_display_hung(adev)) - srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; - - if (srbm_soft_reset) { - tmp = RREG32(mmSRBM_SOFT_RESET); - tmp |= srbm_soft_reset; - dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~srbm_soft_reset; - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - /* Wait a little for things to settle down */ - udelay(50); - } - return 0; -} - static void dce_v6_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, int crtc, enum amdgpu_interrupt_state state) @@ -3224,7 +3168,6 @@ static const struct amd_ip_funcs dce_v6_0_ip_funcs = { .suspend = dce_v6_0_suspend, .resume = dce_v6_0_resume, .is_idle = dce_v6_0_is_idle, - .soft_reset = dce_v6_0_soft_reset, .set_clockgating_state = dce_v6_0_set_clockgating_state, .set_powergating_state = dce_v6_0_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 6d19f6d94d25..c3906270f25e 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -362,35 +362,6 @@ static u32 dce_v8_0_hpd_get_gpio_reg(struct amdgpu_device *adev) return mmDC_GPIO_HPD_A; } -static bool dce_v8_0_is_display_hung(struct amdgpu_device *adev) -{ - u32 crtc_hung = 0; - u32 crtc_status[6]; - u32 i, j, tmp; - - for (i = 0; i < adev->mode_info.num_crtc; i++) { - if (RREG32(mmCRTC_CONTROL + crtc_offsets[i]) & CRTC_CONTROL__CRTC_MASTER_EN_MASK) { - crtc_status[i] = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); - crtc_hung |= (1 << i); - } - } - - for (j = 0; j < 10; j++) { - for (i = 0; i < adev->mode_info.num_crtc; i++) { - if (crtc_hung & (1 << i)) { - tmp = RREG32(mmCRTC_STATUS_HV_COUNT + crtc_offsets[i]); - if (tmp != crtc_status[i]) - crtc_hung &= ~(1 << i); - } - } - if (crtc_hung == 0) - return false; - udelay(100); - } - - return true; -} - static void dce_v8_0_set_vga_render_state(struct amdgpu_device *adev, bool render) { @@ -2873,33 +2844,6 @@ static bool dce_v8_0_is_idle(struct amdgpu_ip_block *ip_block) return true; } -static int dce_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) -{ - u32 srbm_soft_reset = 0, tmp; - struct amdgpu_device *adev = ip_block->adev; - - if (dce_v8_0_is_display_hung(adev)) - srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_DC_MASK; - - if (srbm_soft_reset) { - tmp = RREG32(mmSRBM_SOFT_RESET); - tmp |= srbm_soft_reset; - dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~srbm_soft_reset; - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - /* Wait a little for things to settle down */ - udelay(50); - } - return 0; -} - static void dce_v8_0_set_crtc_vblank_interrupt_state(struct amdgpu_device *adev, int crtc, enum amdgpu_interrupt_state state) @@ -3241,7 +3185,6 @@ static const struct amd_ip_funcs dce_v8_0_ip_funcs = { .suspend = dce_v8_0_suspend, .resume = dce_v8_0_resume, .is_idle = dce_v8_0_is_idle, - .soft_reset = dce_v8_0_soft_reset, .set_clockgating_state = dce_v8_0_set_clockgating_state, .set_powergating_state = dce_v8_0_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 0780c5e5de4f..ddf190672530 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -4022,7 +4022,7 @@ static void gfx_v10_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, WAIT_REG_MEM_ENGINE(eng_sel))); if (mem_space) - BUG_ON(addr0 & 0x3); /* Dword align */ + WARN_ON(addr0 & 0x3); /* Dword align */ amdgpu_ring_write(ring, addr0); amdgpu_ring_write(ring, addr1); amdgpu_ring_write(ring, ref); @@ -7852,6 +7852,8 @@ static int gfx_v10_0_early_init(struct amdgpu_ip_block *ip_block) /* init rlcg reg access ctrl */ gfx_v10_0_init_rlcg_reg_access_ctrl(adev); + amdgpu_init_rlc_reg_funcs(adev); + return gfx_v10_0_init_microcode(adev); } @@ -8658,7 +8660,7 @@ static void gfx_v10_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, header); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -8693,7 +8695,7 @@ static void gfx_v10_0_ring_emit_ib_compute(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -8726,9 +8728,9 @@ static void gfx_v10_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, * aligned if only send 32bit data low (discard data high) */ if (write64bit) - BUG_ON(addr & 0x7); + WARN_ON(addr & 0x7); else - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -8776,9 +8778,6 @@ static void gfx_v10_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, { struct amdgpu_device *adev = ring->adev; - /* we only allocate 32bit for each seq wb address */ - BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - /* write fence seq to the "addr" */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index f856b0cf5bec..2a121df90574 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -133,6 +133,14 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_6_pfp.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_6_me.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_6_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_6_rlc.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_0_pfp.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_0_me.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_0_mec.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_0_rlc.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_1_pfp.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_1_me.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_1_mec.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_1_rlc.bin"); static const struct amdgpu_hwip_reg_entry gc_reg_list_11_0[] = { SOC15_REG_ENTRY_STR(GC, 0, regGRBM_STATUS), @@ -546,7 +554,7 @@ static void gfx_v11_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, WAIT_REG_MEM_ENGINE(eng_sel))); if (mem_space) - BUG_ON(addr0 & 0x3); /* Dword align */ + WARN_ON(addr0 & 0x3); /* Dword align */ amdgpu_ring_write(ring, addr0); amdgpu_ring_write(ring, addr1); amdgpu_ring_write(ring, ref); @@ -1128,6 +1136,8 @@ static int gfx_v11_0_gpu_early_init(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): adev->gfx.config.max_hw_contexts = 8; adev->gfx.config.sc_prim_fifo_size_frontend = 0x20; adev->gfx.config.sc_prim_fifo_size_backend = 0x100; @@ -1612,6 +1622,8 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): adev->gfx.me.num_me = 1; adev->gfx.me.num_pipe_per_me = 1; adev->gfx.me.num_queue_per_pipe = 2; @@ -1911,6 +1923,11 @@ static int gfx_v11_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + adev->gfx.me.use_mmio_for_reset = false; + adev->gfx.mec.use_mmio_for_reset = true; + + mutex_init(&adev->gfx.mec.reset_mutex); + return 0; } @@ -3085,7 +3102,9 @@ static int gfx_v11_0_wait_for_rlc_autoload_complete(struct amdgpu_device *adev) amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 2) || amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 3) || amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 4) || - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 6)) + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 5, 6) || + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 7, 0) || + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(11, 7, 1)) bootload_status = RREG32_SOC15(GC, 0, regRLC_RLCS_BOOTLOAD_STATUS_gc_11_0_1); else @@ -4219,13 +4238,13 @@ static int gfx_v11_0_gfx_mqd_init(struct amdgpu_device *adev, void *m, return 0; } -static int gfx_v11_0_kgq_init_queue(struct amdgpu_ring *ring, bool reset) +static int gfx_v11_0_kgq_init_queue(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; struct v11_gfx_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.gfx_ring[0]; - if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(*mqd)); mutex_lock(&adev->srbm_mutex); soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); @@ -4252,7 +4271,7 @@ static int gfx_v11_0_cp_async_gfx_ring_resume(struct amdgpu_device *adev) int r, i; for (i = 0; i < adev->gfx.num_gfx_rings; i++) { - r = gfx_v11_0_kgq_init_queue(&adev->gfx.gfx_ring[i], false); + r = gfx_v11_0_kgq_init_queue(&adev->gfx.gfx_ring[i]); if (r) return r; } @@ -4589,13 +4608,13 @@ static int gfx_v11_0_kiq_init_queue(struct amdgpu_ring *ring) return 0; } -static int gfx_v11_0_kcq_init_queue(struct amdgpu_ring *ring, bool reset) +static int gfx_v11_0_kcq_init_queue(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; struct v11_compute_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.compute_ring[0]; - if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(*mqd)); mutex_lock(&adev->srbm_mutex); soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); @@ -4632,7 +4651,7 @@ static int gfx_v11_0_kcq_resume(struct amdgpu_device *adev) gfx_v11_0_cp_compute_enable(adev, true); for (i = 0; i < adev->gfx.num_compute_rings; i++) { - r = gfx_v11_0_kcq_init_queue(&adev->gfx.compute_ring[i], false); + r = gfx_v11_0_kcq_init_queue(&adev->gfx.compute_ring[i]); if (r) return r; } @@ -5251,38 +5270,12 @@ static int gfx_v11_0_soft_reset(struct amdgpu_ip_block *ip_block) amdgpu_gfx_rlc_exit_safe_mode(adev, 0); - return gfx_v11_0_cp_resume(adev); -} + r = gfx_v11_0_cp_resume(adev); + if (r) + return r; -static bool gfx_v11_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - int i, r; - struct amdgpu_device *adev = ip_block->adev; - struct amdgpu_ring *ring; - long tmo = msecs_to_jiffies(1000); - - for (i = 0; i < adev->gfx.num_gfx_rings; i++) { - ring = &adev->gfx.gfx_ring[i]; - r = amdgpu_ring_test_ib(ring, tmo); - if (r) - return true; - } - - for (i = 0; i < adev->gfx.num_compute_rings; i++) { - ring = &adev->gfx.compute_ring[i]; - r = amdgpu_ring_test_ib(ring, tmo); - if (r) - return true; - } - - return false; -} - -static int gfx_v11_0_post_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; /** - * GFX soft reset will impact MES, need resume MES when do GFX soft reset + * GFX soft reset impacts MES, resume MES after GFX soft reset is finished */ return amdgpu_mes_resume(adev, 0); } @@ -5406,6 +5399,8 @@ static int gfx_v11_0_early_init(struct amdgpu_ip_block *ip_block) gfx_v11_0_init_rlcg_reg_access_ctrl(adev); + amdgpu_init_rlc_reg_funcs(adev); + return gfx_v11_0_init_microcode(adev); } @@ -5758,6 +5753,8 @@ static void gfx_v11_cntl_power_gating(struct amdgpu_device *adev, bool enable) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): WREG32_SOC15(GC, 0, regRLC_PG_DELAY_3, RLC_PG_DELAY_3_DEFAULT_GC_11_0_1); break; default: @@ -5798,6 +5795,8 @@ static int gfx_v11_0_set_powergating_state(struct amdgpu_ip_block *ip_block, case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): if (!enable) amdgpu_gfx_off_ctrl(adev, false); @@ -5834,6 +5833,8 @@ static int gfx_v11_0_set_clockgating_state(struct amdgpu_ip_block *ip_block, case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): gfx_v11_0_update_gfx_clock_gating(adev, state == AMD_CG_STATE_GATE); break; @@ -5997,7 +5998,7 @@ static void gfx_v11_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, header); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -6032,7 +6033,7 @@ static void gfx_v11_0_ring_emit_ib_compute(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -6065,9 +6066,9 @@ static void gfx_v11_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, * aligned if only send 32bit data low (discard data high) */ if (write64bit) - BUG_ON(addr & 0x7); + WARN_ON(addr & 0x7); else - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -6121,9 +6122,6 @@ static void gfx_v11_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, { struct amdgpu_device *adev = ring->adev; - /* we only allocate 32bit for each seq wb address */ - BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - /* write fence seq to the "addr" */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | @@ -6510,25 +6508,33 @@ static int gfx_v11_0_eop_irq(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { u32 doorbell_offset = entry->src_data[0]; - u8 me_id, pipe_id, queue_id; - struct amdgpu_ring *ring; - int i; DRM_DEBUG("IH: CP EOP\n"); - if (adev->enable_mes && doorbell_offset) { - amdgpu_userq_process_fence_irq(adev, doorbell_offset); - } else { - me_id = (entry->ring_id & 0x0c) >> 2; - pipe_id = (entry->ring_id & 0x03) >> 0; - queue_id = (entry->ring_id & 0x70) >> 4; + if (!adev->gfx.disable_kq) { + u8 me_id = (entry->ring_id & 0x0c) >> 2; + u8 pipe_id = (entry->ring_id & 0x03) >> 0; + u8 queue_id = (entry->ring_id & 0x70) >> 4; + struct amdgpu_ring *ring; + int i; switch (me_id) { case 0: - if (pipe_id == 0) - amdgpu_fence_process(&adev->gfx.gfx_ring[0]); - else - amdgpu_fence_process(&adev->gfx.gfx_ring[1]); + /* + * MES splits gfx HQDs per (me,pipe): KGQ owns queue=0, + * userq gfx owns queue>=1 (see amdgpu_mes_get_hqd_mask). + * Require a strict (me,pipe,queue) match so userq gfx + * EOPs fall through to amdgpu_userq_process_fence_irq(). + */ + for (i = 0; i < adev->gfx.num_gfx_rings; i++) { + ring = &adev->gfx.gfx_ring[i]; + if ((ring->me == me_id) && + (ring->pipe == pipe_id) && + (ring->queue == queue_id)) { + amdgpu_fence_process(ring); + return 0; + } + } break; case 1: case 2: @@ -6540,13 +6546,20 @@ static int gfx_v11_0_eop_irq(struct amdgpu_device *adev, */ if ((ring->me == me_id) && (ring->pipe == pipe_id) && - (ring->queue == queue_id)) + (ring->queue == queue_id)) { amdgpu_fence_process(ring); + return 0; + } } break; + default: + break; } } + if (adev->enable_mes && doorbell_offset) + amdgpu_userq_process_fence_irq(adev, doorbell_offset); + return 0; } @@ -6676,22 +6689,29 @@ static int gfx_v11_0_set_priv_inst_fault_state(struct amdgpu_device *adev, static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { - u8 me_id, pipe_id, queue_id; - struct amdgpu_ring *ring; - int i; - - me_id = (entry->ring_id & 0x0c) >> 2; - pipe_id = (entry->ring_id & 0x03) >> 0; - queue_id = (entry->ring_id & 0x70) >> 4; + u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK; + /* + * Try KQ first by ring_id (HW slot is authoritative). The + * KMD compute_hqd_mask contract guarantees KCQ and user queues + * never share a HW slot. + */ if (!adev->gfx.disable_kq) { + u8 me_id = (entry->ring_id & 0x0c) >> 2; + u8 pipe_id = (entry->ring_id & 0x03) >> 0; + u8 queue_id = (entry->ring_id & 0x70) >> 4; + struct amdgpu_ring *ring; + int i; + switch (me_id) { case 0: for (i = 0; i < adev->gfx.num_gfx_rings; i++) { ring = &adev->gfx.gfx_ring[i]; if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) + ring->queue == queue_id) { drm_sched_fault(&ring->sched); + return; + } } break; case 1: @@ -6699,8 +6719,10 @@ static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev, for (i = 0; i < adev->gfx.num_compute_rings; i++) { ring = &adev->gfx.compute_ring[i]; if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) + ring->queue == queue_id) { drm_sched_fault(&ring->sched); + return; + } } break; default: @@ -6708,6 +6730,11 @@ static void gfx_v11_0_handle_priv_fault(struct amdgpu_device *adev, break; } } + + /* No KQ matched: HW slot is a MES-scheduled user queue. */ + if (adev->enable_mes && doorbell_offset) + amdgpu_userq_process_reset_irq(adev, entry->pasid, + doorbell_offset); } static int gfx_v11_0_priv_reg_irq(struct amdgpu_device *adev, @@ -6814,233 +6841,14 @@ static void gfx_v11_0_emit_mem_sync(struct amdgpu_ring *ring) amdgpu_ring_write(ring, gcr_cntl); /* GCR_CNTL */ } -static bool gfx_v11_pipe_reset_support(struct amdgpu_device *adev) -{ - /* Disable the pipe reset until the CPFW fully support it.*/ - dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n"); - return false; -} - - -static int gfx_v11_reset_gfx_pipe(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - uint32_t reset_pipe = 0, clean_pipe = 0; - int r; - - if (!gfx_v11_pipe_reset_support(adev)) - return -EOPNOTSUPP; - - gfx_v11_0_set_safe_mode(adev, 0); - mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); - - switch (ring->pipe) { - case 0: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - PFP_PIPE0_RESET, 1); - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - ME_PIPE0_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - PFP_PIPE0_RESET, 0); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - ME_PIPE0_RESET, 0); - break; - case 1: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - PFP_PIPE1_RESET, 1); - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - ME_PIPE1_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - PFP_PIPE1_RESET, 0); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - ME_PIPE1_RESET, 0); - break; - default: - break; - } - - WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe); - WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe); - - r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) - - RS64_FW_UC_START_ADDR_LO; - soc21_grbm_select(adev, 0, 0, 0, 0); - mutex_unlock(&adev->srbm_mutex); - gfx_v11_0_unset_safe_mode(adev, 0); - - dev_info(adev->dev, "The ring %s pipe reset to the ME firmware start PC: %s\n", ring->name, - r == 0 ? "successfully" : "failed"); - /* FIXME: Sometimes driver can't cache the ME firmware start PC correctly, - * so the pipe reset status relies on the later gfx ring test result. - */ - return 0; -} - static int gfx_v11_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid, struct amdgpu_fence *timedout_fence) { struct amdgpu_device *adev = ring->adev; - bool use_mmio = false; - int r; + bool use_mmio = adev->gfx.me.use_mmio_for_reset; - amdgpu_ring_reset_helper_begin(ring, timedout_fence); - - r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0); - if (r) { - - dev_warn(adev->dev, "reset via MES failed and try pipe reset %d\n", r); - r = gfx_v11_reset_gfx_pipe(ring); - if (r) - return r; - } - - if (use_mmio) { - r = gfx_v11_0_kgq_init_queue(ring, true); - if (r) { - dev_err(adev->dev, "failed to init kgq\n"); - return r; - } - - r = amdgpu_mes_map_legacy_queue(adev, ring, 0); - if (r) { - dev_err(adev->dev, "failed to remap kgq\n"); - return r; - } - } - - return amdgpu_ring_reset_helper_end(ring, timedout_fence); -} - -static int gfx_v11_0_reset_compute_pipe(struct amdgpu_ring *ring) -{ - - struct amdgpu_device *adev = ring->adev; - uint32_t reset_pipe = 0, clean_pipe = 0; - int r; - - if (!gfx_v11_pipe_reset_support(adev)) - return -EOPNOTSUPP; - - gfx_v11_0_set_safe_mode(adev, 0); - mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); - - reset_pipe = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL); - clean_pipe = reset_pipe; - - if (adev->gfx.rs64_enable) { - - switch (ring->pipe) { - case 0: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE0_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE0_RESET, 0); - break; - case 1: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE1_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE1_RESET, 0); - break; - case 2: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE2_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE2_RESET, 0); - break; - case 3: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE3_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE3_RESET, 0); - break; - default: - break; - } - WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_pipe); - WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_pipe); - r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) - - RS64_FW_UC_START_ADDR_LO; - } else { - if (ring->me == 1) { - switch (ring->pipe) { - case 0: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE0_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE0_RESET, 0); - break; - case 1: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE1_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE1_RESET, 0); - break; - case 2: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE2_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE2_RESET, 0); - break; - case 3: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE3_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE3_RESET, 0); - break; - default: - break; - } - /* mec1 fw pc: CP_MEC1_INSTR_PNTR */ - } else { - switch (ring->pipe) { - case 0: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE0_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE0_RESET, 0); - break; - case 1: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE1_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE1_RESET, 0); - break; - case 2: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE2_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE2_RESET, 0); - break; - case 3: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE3_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME2_PIPE3_RESET, 0); - break; - default: - break; - } - /* mec2 fw pc: CP:CP_MEC2_INSTR_PNTR */ - } - WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_pipe); - WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_pipe); - r = RREG32(SOC15_REG_OFFSET(GC, 0, regCP_MEC1_INSTR_PNTR)); - } - - soc21_grbm_select(adev, 0, 0, 0, 0); - mutex_unlock(&adev->srbm_mutex); - gfx_v11_0_unset_safe_mode(adev, 0); - - dev_info(adev->dev, "The ring %s pipe resets to MEC FW start PC: %s\n", ring->name, - r == 0 ? "successfully" : "failed"); - /*FIXME:Sometimes driver can't cache the MEC firmware start PC correctly, so the pipe - * reset status relies on the compute ring test result. - */ - return 0; + return amdgpu_gfx_mes_reset_queue(ring, vmid, timedout_fence, use_mmio); } static int gfx_v11_0_reset_kcq(struct amdgpu_ring *ring, @@ -7048,30 +6856,8 @@ static int gfx_v11_0_reset_kcq(struct amdgpu_ring *ring, struct amdgpu_fence *timedout_fence) { struct amdgpu_device *adev = ring->adev; - int r = 0; - amdgpu_ring_reset_helper_begin(ring, timedout_fence); - - r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true, 0); - if (r) { - dev_warn(adev->dev, "fail(%d) to reset kcq and try pipe reset\n", r); - r = gfx_v11_0_reset_compute_pipe(ring); - if (r) - return r; - } - - r = gfx_v11_0_kcq_init_queue(ring, true); - if (r) { - dev_err(adev->dev, "fail to init kcq\n"); - return r; - } - r = amdgpu_mes_map_legacy_queue(adev, ring, 0); - if (r) { - dev_err(adev->dev, "failed to remap kcq\n"); - return r; - } - - return amdgpu_ring_reset_helper_end(ring, timedout_fence); + return amdgpu_gfx_reset_mes_compute(adev, ring, timedout_fence, NULL, NULL, NULL); } static void gfx_v11_ip_print(struct amdgpu_ip_block *ip_block, struct drm_printer *p) @@ -7249,8 +7035,6 @@ static const struct amd_ip_funcs gfx_v11_0_ip_funcs = { .is_idle = gfx_v11_0_is_idle, .wait_for_idle = gfx_v11_0_wait_for_idle, .soft_reset = gfx_v11_0_soft_reset, - .check_soft_reset = gfx_v11_0_check_soft_reset, - .post_soft_reset = gfx_v11_0_post_soft_reset, .set_clockgating_state = gfx_v11_0_set_clockgating_state, .set_powergating_state = gfx_v11_0_set_powergating_state, .get_clockgating_state = gfx_v11_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c index f66293fc675e..c765af54669c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_0.c @@ -440,7 +440,7 @@ static void gfx_v12_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, WAIT_REG_MEM_ENGINE(eng_sel))); if (mem_space) - BUG_ON(addr0 & 0x3); /* Dword align */ + WARN_ON(addr0 & 0x3); /* Dword align */ amdgpu_ring_write(ring, addr0); amdgpu_ring_write(ring, addr1); amdgpu_ring_write(ring, ref); @@ -1603,6 +1603,11 @@ static int gfx_v12_0_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + adev->gfx.me.use_mmio_for_reset = false; + adev->gfx.mec.use_mmio_for_reset = true; + + mutex_init(&adev->gfx.mec.reset_mutex); + return 0; } @@ -3071,13 +3076,13 @@ static int gfx_v12_0_gfx_mqd_init(struct amdgpu_device *adev, void *m, return 0; } -static int gfx_v12_0_kgq_init_queue(struct amdgpu_ring *ring, bool reset) +static int gfx_v12_0_kgq_init_queue(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; struct v12_gfx_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.gfx_ring[0]; - if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(*mqd)); mutex_lock(&adev->srbm_mutex); soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); @@ -3104,7 +3109,7 @@ static int gfx_v12_0_cp_async_gfx_ring_resume(struct amdgpu_device *adev) int i, r; for (i = 0; i < adev->gfx.num_gfx_rings; i++) { - r = gfx_v12_0_kgq_init_queue(&adev->gfx.gfx_ring[i], false); + r = gfx_v12_0_kgq_init_queue(&adev->gfx.gfx_ring[i]); if (r) return r; } @@ -3441,13 +3446,13 @@ static int gfx_v12_0_kiq_init_queue(struct amdgpu_ring *ring) return 0; } -static int gfx_v12_0_kcq_init_queue(struct amdgpu_ring *ring, bool reset) +static int gfx_v12_0_kcq_init_queue(struct amdgpu_ring *ring) { struct amdgpu_device *adev = ring->adev; struct v12_compute_mqd *mqd = ring->mqd_ptr; int mqd_idx = ring - &adev->gfx.compute_ring[0]; - if (!reset && !amdgpu_in_reset(adev) && !adev->in_suspend) { + if (!amdgpu_in_reset(adev) && !adev->in_suspend) { memset((void *)mqd, 0, sizeof(*mqd)); mutex_lock(&adev->srbm_mutex); soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); @@ -3485,7 +3490,7 @@ static int gfx_v12_0_kcq_resume(struct amdgpu_device *adev) gfx_v12_0_cp_compute_enable(adev, true); for (i = 0; i < adev->gfx.num_compute_rings; i++) { - r = gfx_v12_0_kcq_init_queue(&adev->gfx.compute_ring[i], false); + r = gfx_v12_0_kcq_init_queue(&adev->gfx.compute_ring[i]); if (r) return r; } @@ -3519,10 +3524,19 @@ static int gfx_v12_0_cp_resume(struct amdgpu_device *adev) gfx_v12_0_cp_gfx_enable(adev, true); } - if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) + if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) { r = amdgpu_mes_kiq_hw_init(adev, 0); - else + /* + * With MES, GFX KIQ ring is owned by the MES and is never + * initialized/used directly by the driver, so it must + * not be left flagged as ready. mes_v12_0_hw_init() clears + * but clear here if MES init fails + */ + if (r) + adev->gfx.kiq[0].ring.sched.ready = false; + } else { r = gfx_v12_0_kiq_resume(adev); + } if (r) return r; @@ -3977,6 +3991,8 @@ static int gfx_v12_0_early_init(struct amdgpu_ip_block *ip_block) gfx_v12_0_init_rlcg_reg_access_ctrl(adev); + amdgpu_init_rlc_reg_funcs(adev); + return gfx_v12_0_init_microcode(adev); } @@ -4493,7 +4509,7 @@ static void gfx_v12_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, control |= ib->length_dw | (vmid << 24); amdgpu_ring_write(ring, header); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -4512,7 +4528,7 @@ static void gfx_v12_0_ring_emit_ib_compute(struct amdgpu_ring *ring, u32 control = INDIRECT_BUFFER_VALID | ib->length_dw | (vmid << 24); amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -4543,9 +4559,9 @@ static void gfx_v12_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, * aligned if only send 32bit data low (discard data high) */ if (write64bit) - BUG_ON(addr & 0x7); + WARN_ON(addr & 0x7); else - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -4593,9 +4609,6 @@ static void gfx_v12_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, { struct amdgpu_device *adev = ring->adev; - /* we only allocate 32bit for each seq wb address */ - BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - /* write fence seq to the "addr" */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | @@ -4838,25 +4851,33 @@ static int gfx_v12_0_eop_irq(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { u32 doorbell_offset = entry->src_data[0]; - u8 me_id, pipe_id, queue_id; - struct amdgpu_ring *ring; - int i; DRM_DEBUG("IH: CP EOP\n"); - if (adev->enable_mes && doorbell_offset) { - amdgpu_userq_process_fence_irq(adev, doorbell_offset); - } else { - me_id = (entry->ring_id & 0x0c) >> 2; - pipe_id = (entry->ring_id & 0x03) >> 0; - queue_id = (entry->ring_id & 0x70) >> 4; + if (!adev->gfx.disable_kq) { + u8 me_id = (entry->ring_id & 0x0c) >> 2; + u8 pipe_id = (entry->ring_id & 0x03) >> 0; + u8 queue_id = (entry->ring_id & 0x70) >> 4; + struct amdgpu_ring *ring; + int i; switch (me_id) { case 0: - if (pipe_id == 0) - amdgpu_fence_process(&adev->gfx.gfx_ring[0]); - else - amdgpu_fence_process(&adev->gfx.gfx_ring[1]); + /* + * MES splits gfx HQDs per (me,pipe): KGQ owns queue=0, + * userq gfx owns queue>=1 (see amdgpu_mes_get_hqd_mask). + * Require a strict (me,pipe,queue) match so userq gfx + * EOPs fall through to amdgpu_userq_process_fence_irq(). + */ + for (i = 0; i < adev->gfx.num_gfx_rings; i++) { + ring = &adev->gfx.gfx_ring[i]; + if ((ring->me == me_id) && + (ring->pipe == pipe_id) && + (ring->queue == queue_id)) { + amdgpu_fence_process(ring); + return 0; + } + } break; case 1: case 2: @@ -4868,13 +4889,20 @@ static int gfx_v12_0_eop_irq(struct amdgpu_device *adev, */ if ((ring->me == me_id) && (ring->pipe == pipe_id) && - (ring->queue == queue_id)) + (ring->queue == queue_id)) { amdgpu_fence_process(ring); + return 0; + } } break; + default: + break; } } + if (adev->enable_mes && doorbell_offset) + amdgpu_userq_process_fence_irq(adev, doorbell_offset); + return 0; } @@ -5004,22 +5032,30 @@ static int gfx_v12_0_set_priv_inst_fault_state(struct amdgpu_device *adev, static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev, struct amdgpu_iv_entry *entry) { - u8 me_id, pipe_id, queue_id; - struct amdgpu_ring *ring; - int i; - - me_id = (entry->ring_id & 0x0c) >> 2; - pipe_id = (entry->ring_id & 0x03) >> 0; - queue_id = (entry->ring_id & 0x70) >> 4; + u32 doorbell_offset = entry->src_data[0] & AMDGPU_CTXID0_DOORBELL_ID_MASK; + /* + * Try KQ first by ring_id; UQ as fallback. KCQ and UQ never share + * a HW slot (compute_hqd_mask contract). + */ if (!adev->gfx.disable_kq) { + u8 me_id, pipe_id, queue_id; + struct amdgpu_ring *ring; + int i; + + me_id = (entry->ring_id & 0x0c) >> 2; + pipe_id = (entry->ring_id & 0x03) >> 0; + queue_id = (entry->ring_id & 0x70) >> 4; + switch (me_id) { case 0: for (i = 0; i < adev->gfx.num_gfx_rings; i++) { ring = &adev->gfx.gfx_ring[i]; if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) + ring->queue == queue_id) { drm_sched_fault(&ring->sched); + return; + } } break; case 1: @@ -5027,8 +5063,10 @@ static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev, for (i = 0; i < adev->gfx.num_compute_rings; i++) { ring = &adev->gfx.compute_ring[i]; if (ring->me == me_id && ring->pipe == pipe_id && - ring->queue == queue_id) + ring->queue == queue_id) { drm_sched_fault(&ring->sched); + return; + } } break; default: @@ -5036,6 +5074,11 @@ static void gfx_v12_0_handle_priv_fault(struct amdgpu_device *adev, break; } } + + /* No KQ matched: HW slot is a MES-scheduled user queue. */ + if (adev->enable_mes && doorbell_offset) + amdgpu_userq_process_reset_irq(adev, entry->pasid, + doorbell_offset); } static int gfx_v12_0_priv_reg_irq(struct amdgpu_device *adev, @@ -5240,185 +5283,14 @@ static void gfx_v12_ip_dump(struct amdgpu_ip_block *ip_block) amdgpu_gfx_off_ctrl(adev, true); } -static bool gfx_v12_pipe_reset_support(struct amdgpu_device *adev) -{ - /* Disable the pipe reset until the CPFW fully support it.*/ - dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n"); - return false; -} - -static int gfx_v12_reset_gfx_pipe(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - uint32_t reset_pipe = 0, clean_pipe = 0; - int r; - - if (!gfx_v12_pipe_reset_support(adev)) - return -EOPNOTSUPP; - - gfx_v12_0_set_safe_mode(adev, 0); - mutex_lock(&adev->srbm_mutex); - soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); - - switch (ring->pipe) { - case 0: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - PFP_PIPE0_RESET, 1); - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - ME_PIPE0_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - PFP_PIPE0_RESET, 0); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - ME_PIPE0_RESET, 0); - break; - case 1: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - PFP_PIPE1_RESET, 1); - reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, - ME_PIPE1_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - PFP_PIPE1_RESET, 0); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, - ME_PIPE1_RESET, 0); - break; - default: - break; - } - - WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe); - WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe); - - r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) - - RS64_FW_UC_START_ADDR_LO; - soc24_grbm_select(adev, 0, 0, 0, 0); - mutex_unlock(&adev->srbm_mutex); - gfx_v12_0_unset_safe_mode(adev, 0); - - dev_info(adev->dev, "The ring %s pipe reset: %s\n", ring->name, - r == 0 ? "successfully" : "failed"); - /* Sometimes the ME start pc counter can't cache correctly, so the - * PC check only as a reference and pipe reset result rely on the - * later ring test. - */ - return 0; -} - static int gfx_v12_0_reset_kgq(struct amdgpu_ring *ring, unsigned int vmid, struct amdgpu_fence *timedout_fence) { struct amdgpu_device *adev = ring->adev; - bool use_mmio = false; - int r; + bool use_mmio = adev->gfx.me.use_mmio_for_reset; - amdgpu_ring_reset_helper_begin(ring, timedout_fence); - - r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, use_mmio, 0); - if (r) { - dev_warn(adev->dev, "reset via MES failed and try pipe reset %d\n", r); - r = gfx_v12_reset_gfx_pipe(ring); - if (r) - return r; - } - - if (use_mmio) { - r = gfx_v12_0_kgq_init_queue(ring, true); - if (r) { - dev_err(adev->dev, "failed to init kgq\n"); - return r; - } - - r = amdgpu_mes_map_legacy_queue(adev, ring, 0); - if (r) { - dev_err(adev->dev, "failed to remap kgq\n"); - return r; - } - } - - return amdgpu_ring_reset_helper_end(ring, timedout_fence); -} - -static int gfx_v12_0_reset_compute_pipe(struct amdgpu_ring *ring) -{ - struct amdgpu_device *adev = ring->adev; - uint32_t reset_pipe = 0, clean_pipe = 0; - int r = 0; - - if (!gfx_v12_pipe_reset_support(adev)) - return -EOPNOTSUPP; - - gfx_v12_0_set_safe_mode(adev, 0); - mutex_lock(&adev->srbm_mutex); - soc24_grbm_select(adev, ring->me, ring->pipe, ring->queue, 0); - - reset_pipe = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL); - clean_pipe = reset_pipe; - - if (adev->gfx.rs64_enable) { - switch (ring->pipe) { - case 0: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE0_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE0_RESET, 0); - break; - case 1: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE1_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE1_RESET, 0); - break; - case 2: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE2_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE2_RESET, 0); - break; - case 3: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE3_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_RS64_CNTL, - MEC_PIPE3_RESET, 0); - break; - default: - break; - } - WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_pipe); - WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_pipe); - r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) - - RS64_FW_UC_START_ADDR_LO; - } else { - switch (ring->pipe) { - case 0: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE0_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE0_RESET, 0); - break; - case 1: - reset_pipe = REG_SET_FIELD(reset_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE1_RESET, 1); - clean_pipe = REG_SET_FIELD(clean_pipe, CP_MEC_CNTL, - MEC_ME1_PIPE1_RESET, 0); - break; - default: - break; - } - WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_pipe); - WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_pipe); - /* Doesn't find the F32 MEC instruction pointer register, and suppose - * the driver won't run into the F32 mode. - */ - } - - soc24_grbm_select(adev, 0, 0, 0, 0); - mutex_unlock(&adev->srbm_mutex); - gfx_v12_0_unset_safe_mode(adev, 0); - - dev_info(adev->dev, "The ring %s pipe resets: %s\n", ring->name, - r == 0 ? "successfully" : "failed"); - /* Need the ring test to verify the pipe reset result.*/ - return 0; + return amdgpu_gfx_mes_reset_queue(ring, vmid, timedout_fence, use_mmio); } static int gfx_v12_0_reset_kcq(struct amdgpu_ring *ring, @@ -5426,30 +5298,8 @@ static int gfx_v12_0_reset_kcq(struct amdgpu_ring *ring, struct amdgpu_fence *timedout_fence) { struct amdgpu_device *adev = ring->adev; - int r; - amdgpu_ring_reset_helper_begin(ring, timedout_fence); - - r = amdgpu_mes_reset_legacy_queue(ring->adev, ring, vmid, true, 0); - if (r) { - dev_warn(adev->dev, "fail(%d) to reset kcq and try pipe reset\n", r); - r = gfx_v12_0_reset_compute_pipe(ring); - if (r) - return r; - } - - r = gfx_v12_0_kcq_init_queue(ring, true); - if (r) { - dev_err(adev->dev, "failed to init kcq\n"); - return r; - } - r = amdgpu_mes_map_legacy_queue(adev, ring, 0); - if (r) { - dev_err(adev->dev, "failed to remap kcq\n"); - return r; - } - - return amdgpu_ring_reset_helper_end(ring, timedout_fence); + return amdgpu_gfx_reset_mes_compute(adev, ring, timedout_fence, NULL, NULL, NULL); } static void gfx_v12_0_ring_begin_use(struct amdgpu_ring *ring) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c index 61c3577f829f..e87f1baf5cb6 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v12_1.c @@ -248,7 +248,7 @@ static void gfx_v12_1_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, PACKET3_WAIT_REG_MEM__FUNCTION(3))); /* equal */ if (mem_space) - BUG_ON(addr0 & 0x3); /* Dword align */ + WARN_ON(addr0 & 0x3); /* Dword align */ amdgpu_ring_write(ring, addr0); amdgpu_ring_write(ring, addr1); amdgpu_ring_write(ring, ref); @@ -1287,6 +1287,8 @@ static int gfx_v12_1_sw_init(struct amdgpu_ip_block *ip_block) if (r) return r; + mutex_init(&adev->gfx.mec.reset_mutex); + return 0; } @@ -2547,10 +2549,19 @@ static int gfx_v12_1_xcc_cp_resume(struct amdgpu_device *adev, uint16_t xcc_mask gfx_v12_1_xcc_cp_compute_enable(adev, true, xcc_id); - if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) + if (adev->enable_mes_kiq && adev->mes.kiq_hw_init) { r = amdgpu_mes_kiq_hw_init(adev, xcc_id); - else + /* + * With MES, GFX KIQ ring is owned by the MES and is never + * initialized/used directly by the driver, so it must + * not be left flagged as ready. mes_v12_0_hw_init() clears + * but clear here if MES init fails + */ + if (r) + adev->gfx.kiq[xcc_id].ring.sched.ready = false; + } else { r = gfx_v12_1_xcc_kiq_resume(adev, xcc_id); + } if (r) return r; @@ -2995,6 +3006,8 @@ static int gfx_v12_1_early_init(struct amdgpu_ip_block *ip_block) gfx_v12_1_init_rlcg_reg_access_ctrl(adev); + amdgpu_init_rlc_reg_funcs(adev); + return gfx_v12_1_init_microcode(adev); } @@ -3433,7 +3446,7 @@ static void gfx_v12_1_ring_emit_ib_compute(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -3466,9 +3479,9 @@ static void gfx_v12_1_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, * aligned if only send 32bit data low (discard data high) */ if (write64bit) - BUG_ON(addr & 0x7); + WARN_ON(addr & 0x7); else - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -3515,9 +3528,6 @@ static void gfx_v12_1_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, { struct amdgpu_device *adev = ring->adev; - /* we only allocate 32bit for each seq wb address */ - BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - /* write fence seq to the "addr" */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); amdgpu_ring_write(ring, (PACKET3_WRITE_DATA__DST_SEL(5) | PACKET3_WRITE_DATA__WR_CONFIRM(1))); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 130196859ff3..bee2ff6865f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -1487,7 +1487,14 @@ static int gfx_v8_0_do_edc_gpr_workarounds(struct amdgpu_device *adev) /* bail if the compute ring is not ready */ if (!ring->sched.ready) - return 0; + return -EBUSY; + + if (amdgpu_in_reset(adev)) { + /* Set preempt condition to execute IB */ + amdgpu_ring_set_preempt_cond_exec(ring, true); + /* Flush HDP cache so the GPU can see the updated COND_EXEC value */ + amdgpu_device_flush_hdp(adev, NULL); + } tmp = RREG32(mmGB_EDC_MODE); WREG32(mmGB_EDC_MODE, 0); @@ -2028,6 +2035,11 @@ static int gfx_v8_0_sw_init(struct amdgpu_ip_block *ip_block) adev->gfx.compute_supported_reset = amdgpu_get_soft_full_reset_mask(&adev->gfx.compute_ring[0]); + if (!amdgpu_sriov_vf(adev) && !adev->debug_disable_ip_block_soft_reset) { + adev->gfx.compute_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET; + adev->gfx.gfx_supported_reset |= AMDGPU_RESET_TYPE_IP_BLOCK_SOFT_RESET; + } + return 0; } @@ -4703,12 +4715,14 @@ static int gfx_v8_0_cp_test_all_rings(struct amdgpu_device *adev) if (r) return r; + r = 0; + for (i = 0; i < adev->gfx.num_compute_rings; i++) { ring = &adev->gfx.compute_ring[i]; - amdgpu_ring_test_helper(ring); + r |= amdgpu_ring_test_helper(ring); } - return 0; + return r; } static int gfx_v8_0_cp_resume(struct amdgpu_device *adev) @@ -4868,14 +4882,12 @@ static int gfx_v8_0_hw_fini(struct amdgpu_ip_block *ip_block) } amdgpu_gfx_rlc_enter_safe_mode(adev, 0); - if (!gfx_v8_0_wait_for_idle(ip_block)) - gfx_v8_0_cp_enable(adev, false); - else + if (!amdgpu_in_reset(adev) && gfx_v8_0_wait_for_idle(ip_block)) pr_err("cp is busy, skip halt cp\n"); - if (!gfx_v8_0_wait_for_rlc_idle(adev)) - adev->gfx.rlc.funcs->stop(adev); - else - pr_err("rlc is busy, skip halt rlc\n"); + if (!amdgpu_in_reset(adev) && gfx_v8_0_wait_for_rlc_idle(adev)) + pr_err("rlc is busy\n"); + gfx_v8_0_cp_enable(adev, false); + adev->gfx.rlc.funcs->stop(adev); amdgpu_gfx_rlc_exit_safe_mode(adev, 0); return 0; @@ -4891,128 +4903,49 @@ static int gfx_v8_0_resume(struct amdgpu_ip_block *ip_block) return gfx_v8_0_hw_init(ip_block); } -static bool gfx_v8_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 grbm_soft_reset = 0, srbm_soft_reset = 0; - u32 tmp; - - /* GRBM_STATUS */ - tmp = RREG32(mmGRBM_STATUS); - if (tmp & (GRBM_STATUS__PA_BUSY_MASK | GRBM_STATUS__SC_BUSY_MASK | - GRBM_STATUS__BCI_BUSY_MASK | GRBM_STATUS__SX_BUSY_MASK | - GRBM_STATUS__TA_BUSY_MASK | GRBM_STATUS__VGT_BUSY_MASK | - GRBM_STATUS__DB_BUSY_MASK | GRBM_STATUS__CB_BUSY_MASK | - GRBM_STATUS__GDS_BUSY_MASK | GRBM_STATUS__SPI_BUSY_MASK | - GRBM_STATUS__IA_BUSY_MASK | GRBM_STATUS__IA_BUSY_NO_DMA_MASK | - GRBM_STATUS__CP_BUSY_MASK | GRBM_STATUS__CP_COHERENCY_BUSY_MASK)) { - grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, - GRBM_SOFT_RESET, SOFT_RESET_CP, 1); - grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, - GRBM_SOFT_RESET, SOFT_RESET_GFX, 1); - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, - SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1); - } - - /* GRBM_STATUS2 */ - tmp = RREG32(mmGRBM_STATUS2); - if (REG_GET_FIELD(tmp, GRBM_STATUS2, RLC_BUSY)) - grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, - GRBM_SOFT_RESET, SOFT_RESET_RLC, 1); - - if (REG_GET_FIELD(tmp, GRBM_STATUS2, CPF_BUSY) || - REG_GET_FIELD(tmp, GRBM_STATUS2, CPC_BUSY) || - REG_GET_FIELD(tmp, GRBM_STATUS2, CPG_BUSY)) { - grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, - SOFT_RESET_CPF, 1); - grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, - SOFT_RESET_CPC, 1); - grbm_soft_reset = REG_SET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, - SOFT_RESET_CPG, 1); - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, - SOFT_RESET_GRBM, 1); - } - - /* SRBM_STATUS */ - tmp = RREG32(mmSRBM_STATUS); - if (REG_GET_FIELD(tmp, SRBM_STATUS, GRBM_RQ_PENDING)) - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, - SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1); - if (REG_GET_FIELD(tmp, SRBM_STATUS, SEM_BUSY)) - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, - SRBM_SOFT_RESET, SOFT_RESET_SEM, 1); - - if (grbm_soft_reset || srbm_soft_reset) { - adev->gfx.grbm_soft_reset = grbm_soft_reset; - adev->gfx.srbm_soft_reset = srbm_soft_reset; - return true; - } else { - adev->gfx.grbm_soft_reset = 0; - adev->gfx.srbm_soft_reset = 0; - return false; - } -} - -static int gfx_v8_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 grbm_soft_reset = 0; - - if ((!adev->gfx.grbm_soft_reset) && - (!adev->gfx.srbm_soft_reset)) - return 0; - - grbm_soft_reset = adev->gfx.grbm_soft_reset; - - /* stop the rlc */ - adev->gfx.rlc.funcs->stop(adev); - - if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX)) - /* Disable GFX parsing/prefetching */ - gfx_v8_0_cp_gfx_enable(adev, false); - - if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) { - int i; - - for (i = 0; i < adev->gfx.num_compute_rings; i++) { - struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; - - mutex_lock(&adev->srbm_mutex); - vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); - gfx_v8_0_deactivate_hqd(adev, 2); - vi_srbm_select(adev, 0, 0, 0, 0); - mutex_unlock(&adev->srbm_mutex); - } - /* Disable MEC parsing/prefetching */ - gfx_v8_0_cp_compute_enable(adev, false); - } - - return 0; -} - static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; u32 grbm_soft_reset = 0, srbm_soft_reset = 0; u32 tmp; + int i; + int r; - if ((!adev->gfx.grbm_soft_reset) && - (!adev->gfx.srbm_soft_reset)) - return 0; + grbm_soft_reset = + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_RLC, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_GFX, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CP, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPF, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPC, 1) | + REG_SET_FIELD(0, GRBM_SOFT_RESET, SOFT_RESET_CPG, 1); - grbm_soft_reset = adev->gfx.grbm_soft_reset; - srbm_soft_reset = adev->gfx.srbm_soft_reset; + srbm_soft_reset = + REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_GRBM, 1) | + REG_SET_FIELD(0, SRBM_SOFT_RESET, SOFT_RESET_SEM, 1); + + for (i = 0; i < adev->gfx.num_compute_rings; i++) { + struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; + + mutex_lock(&adev->srbm_mutex); + vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); + gfx_v8_0_deactivate_hqd(adev, 2); + vi_srbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + + udelay(50); + } + + ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_UNGATE); + ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_UNGATE); + ip_block->version->funcs->suspend(ip_block); if (grbm_soft_reset || srbm_soft_reset) { tmp = RREG32(mmGMCON_DEBUG); tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_STALL, 1); tmp = REG_SET_FIELD(tmp, GMCON_DEBUG, GFX_CLEAR, 1); WREG32(mmGMCON_DEBUG, tmp); - udelay(50); + + udelay(100); } if (grbm_soft_reset) { @@ -5022,11 +4955,13 @@ static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) WREG32(mmGRBM_SOFT_RESET, tmp); tmp = RREG32(mmGRBM_SOFT_RESET); - udelay(50); + udelay(100); tmp &= ~grbm_soft_reset; WREG32(mmGRBM_SOFT_RESET, tmp); tmp = RREG32(mmGRBM_SOFT_RESET); + + udelay(100); } if (srbm_soft_reset) { @@ -5036,11 +4971,13 @@ static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) WREG32(mmSRBM_SOFT_RESET, tmp); tmp = RREG32(mmSRBM_SOFT_RESET); - udelay(50); + udelay(100); tmp &= ~srbm_soft_reset; WREG32(mmSRBM_SOFT_RESET, tmp); tmp = RREG32(mmSRBM_SOFT_RESET); + + udelay(100); } if (grbm_soft_reset || srbm_soft_reset) { @@ -5051,48 +4988,15 @@ static int gfx_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) } /* Wait a little for things to settle down */ - udelay(50); + udelay(100); - return 0; -} + r = ip_block->version->funcs->resume(ip_block); + r |= ip_block->version->funcs->late_init(ip_block); + if (r) + return r; -static int gfx_v8_0_post_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 grbm_soft_reset = 0; - - if ((!adev->gfx.grbm_soft_reset) && - (!adev->gfx.srbm_soft_reset)) - return 0; - - grbm_soft_reset = adev->gfx.grbm_soft_reset; - - if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPF) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPC) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CPG)) { - int i; - - for (i = 0; i < adev->gfx.num_compute_rings; i++) { - struct amdgpu_ring *ring = &adev->gfx.compute_ring[i]; - - mutex_lock(&adev->srbm_mutex); - vi_srbm_select(adev, ring->me, ring->pipe, ring->queue, 0); - gfx_v8_0_deactivate_hqd(adev, 2); - vi_srbm_select(adev, 0, 0, 0, 0); - mutex_unlock(&adev->srbm_mutex); - } - gfx_v8_0_kiq_resume(adev); - gfx_v8_0_kcq_resume(adev); - } - - if (REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_CP) || - REG_GET_FIELD(grbm_soft_reset, GRBM_SOFT_RESET, SOFT_RESET_GFX)) - gfx_v8_0_cp_gfx_resume(adev); - - gfx_v8_0_cp_test_all_rings(adev); - - adev->gfx.rlc.funcs->start(adev); + ip_block->version->funcs->set_clockgating_state(ip_block, AMD_CG_STATE_GATE); + ip_block->version->funcs->set_powergating_state(ip_block, AMD_PG_STATE_GATE); return 0; } @@ -6256,9 +6160,6 @@ static void gfx_v8_0_ring_emit_fence_compute(struct amdgpu_ring *ring, static void gfx_v8_0_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, u64 seq, unsigned int flags) { - /* we only allocate 32bit for each seq wb address */ - BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - /* write fence seq to the "addr" */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | @@ -6862,10 +6763,7 @@ static const struct amd_ip_funcs gfx_v8_0_ip_funcs = { .resume = gfx_v8_0_resume, .is_idle = gfx_v8_0_is_idle, .wait_for_idle = gfx_v8_0_wait_for_idle, - .check_soft_reset = gfx_v8_0_check_soft_reset, - .pre_soft_reset = gfx_v8_0_pre_soft_reset, .soft_reset = gfx_v8_0_soft_reset, - .post_soft_reset = gfx_v8_0_post_soft_reset, .set_clockgating_state = gfx_v8_0_set_clockgating_state, .set_powergating_state = gfx_v8_0_set_powergating_state, .get_clockgating_state = gfx_v8_0_get_clockgating_state, @@ -6926,10 +6824,12 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { .get_wptr = gfx_v8_0_ring_get_wptr_compute, .set_wptr = gfx_v8_0_ring_set_wptr_compute, .emit_frame_size = + 5 + /* gfx_v8_0_ring_emit_init_cond_exec (from amdgpu_ib_schedule) */ 20 + /* gfx_v8_0_ring_emit_gds_switch */ 7 + /* gfx_v8_0_ring_emit_hdp_flush */ 5 + /* hdp_invalidate */ 7 + /* gfx_v8_0_ring_emit_pipeline_sync */ + 5 + /* gfx_v8_0_ring_emit_init_cond_exec (from amdgpu_vm_flush) */ VI_FLUSH_GPU_TLB_NUM_WREG * 5 + 7 + /* gfx_v8_0_ring_emit_vm_flush */ 7 + 7 + 7 + /* gfx_v8_0_ring_emit_fence_compute x3 for user fence, vm fence */ 7 + /* gfx_v8_0_emit_mem_sync_compute */ @@ -6950,6 +6850,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { .soft_recovery = gfx_v8_0_ring_soft_recovery, .emit_mem_sync = gfx_v8_0_emit_mem_sync_compute, .emit_wave_limit = gfx_v8_0_emit_wave_limit, + .init_cond_exec = gfx_v8_0_ring_emit_init_cond_exec, }; static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_kiq = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 81a759a98725..9f81fd715418 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1183,7 +1183,7 @@ static void gfx_v9_0_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, WAIT_REG_MEM_ENGINE(eng_sel))); if (mem_space) - BUG_ON(addr0 & 0x3); /* Dword align */ + WARN_ON(addr0 & 0x3); /* Dword align */ amdgpu_ring_write(ring, addr0); amdgpu_ring_write(ring, addr1); amdgpu_ring_write(ring, ref); @@ -4875,6 +4875,8 @@ static int gfx_v9_0_early_init(struct amdgpu_ip_block *ip_block) /* init rlcg reg access ctrl */ gfx_v9_0_init_rlcg_reg_access_ctrl(adev); + amdgpu_init_rlc_reg_funcs(adev); + return gfx_v9_0_init_microcode(adev); } @@ -5474,7 +5476,7 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, header); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -5570,7 +5572,7 @@ static void gfx_v9_0_ring_emit_ib_compute(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -5611,9 +5613,9 @@ static void gfx_v9_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, * aligned if only send 32bit data low (discard data high) */ if (write64bit) - BUG_ON(addr & 0x7); + WARN_ON(addr & 0x7); else - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 510266ba0c38..b89cbc2df951 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -39,7 +39,6 @@ #include "gfx_v9_4_3.h" #include "gfx_v9_4_3_cleaner_shader.h" #include "amdgpu_xcp.h" -#include "amdgpu_aca.h" MODULE_FIRMWARE("amdgpu/gc_9_4_3_mec.bin"); MODULE_FIRMWARE("amdgpu/gc_9_4_4_mec.bin"); @@ -405,7 +404,7 @@ static void gfx_v9_4_3_wait_reg_mem(struct amdgpu_ring *ring, int eng_sel, WAIT_REG_MEM_ENGINE(eng_sel))); if (mem_space) - BUG_ON(addr0 & 0x3); /* Dword align */ + WARN_ON(addr0 & 0x3); /* Dword align */ amdgpu_ring_write(ring, addr0); amdgpu_ring_write(ring, addr1); amdgpu_ring_write(ring, ref); @@ -851,73 +850,6 @@ static const struct amdgpu_gfx_funcs gfx_v9_4_3_gfx_funcs = { .get_hdp_flush_mask = &amdgpu_gfx_get_hdp_flush_mask, }; -static int gfx_v9_4_3_aca_bank_parser(struct aca_handle *handle, - struct aca_bank *bank, enum aca_smu_type type, - void *data) -{ - struct aca_bank_info info; - u64 misc0; - u32 instlo; - int ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - /* NOTE: overwrite info.die_id with xcd id for gfx */ - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - info.die_id = instlo == mmSMNAID_XCD0_MCA_SMU ? 0 : 1; - - misc0 = bank->regs[ACA_REG_IDX_MISC0]; - - switch (type) { - case ACA_SMU_TYPE_UE: - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, 1ULL); - break; - case ACA_SMU_TYPE_CE: - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, - ACA_REG__MISC0__ERRCNT(misc0)); - break; - default: - return -EINVAL; - } - - return ret; -} - -static bool gfx_v9_4_3_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - u32 instlo; - - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - switch (instlo) { - case mmSMNAID_XCD0_MCA_SMU: - case mmSMNAID_XCD1_MCA_SMU: - case mmSMNXCD_XCD0_MCA_SMU: - return true; - default: - break; - } - - return false; -} - -static const struct aca_bank_ops gfx_v9_4_3_aca_bank_ops = { - .aca_bank_parser = gfx_v9_4_3_aca_bank_parser, - .aca_bank_is_valid = gfx_v9_4_3_aca_bank_is_valid, -}; - -static const struct aca_info gfx_v9_4_3_aca_info = { - .hwip = ACA_HWIP_TYPE_SMU, - .mask = ACA_ERROR_UE_MASK | ACA_ERROR_CE_MASK, - .bank_ops = &gfx_v9_4_3_aca_bank_ops, -}; - static int gfx_v9_4_3_gpu_early_init(struct amdgpu_device *adev) { adev->gfx.funcs = &gfx_v9_4_3_gfx_funcs; @@ -1107,22 +1039,24 @@ static int gfx_v9_4_3_sw_init(struct amdgpu_ip_block *ip_block) /* set up the compute queues - allocate horizontally across pipes */ for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) { ring_id = 0; - for (i = 0; i < adev->gfx.mec.num_mec; ++i) { - for (j = 0; j < adev->gfx.mec.num_queue_per_pipe; j++) { - for (k = 0; k < adev->gfx.mec.num_pipe_per_mec; - k++) { - if (!amdgpu_gfx_is_mec_queue_enabled( - adev, xcc_id, i, k, j)) - continue; + if (!adev->gfx.disable_kq) { + for (i = 0; i < adev->gfx.mec.num_mec; ++i) { + for (j = 0; j < adev->gfx.mec.num_queue_per_pipe; j++) { + for (k = 0; k < adev->gfx.mec.num_pipe_per_mec; + k++) { + if (!amdgpu_gfx_is_mec_queue_enabled( + adev, xcc_id, i, k, j)) + continue; - r = gfx_v9_4_3_compute_ring_init(adev, - ring_id, - xcc_id, - i, k, j); - if (r) - return r; + r = gfx_v9_4_3_compute_ring_init(adev, + ring_id, + xcc_id, + i, k, j); + if (r) + return r; - ring_id++; + ring_id++; + } } } } @@ -2350,6 +2284,65 @@ static void gfx_v9_4_3_xcc_fini(struct amdgpu_device *adev, int xcc_id) gfx_v9_4_3_xcc_cp_compute_enable(adev, false, xcc_id); } +static int gfx_v9_4_3_set_userq_eop_interrupts(struct amdgpu_device *adev, + bool enable) +{ + int num_xcc = NUM_XCC(adev->gfx.xcc_mask); + unsigned int irq_type; + int m, p, xcc_id, r; + + if (adev->gfx.disable_kq) { + for (xcc_id = 0; xcc_id < num_xcc; xcc_id++) { + for (m = 0; m < adev->gfx.mec.num_mec; ++m) { + for (p = 0; p < adev->gfx.mec.num_pipe_per_mec; p++) { + irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP + + (m * adev->gfx.mec.num_pipe_per_mec) + + p; + + if (enable) + r = amdgpu_irq_get(adev, &adev->gfx.eop_irq, + irq_type); + else + r = amdgpu_irq_put(adev, &adev->gfx.eop_irq, + irq_type); + if (r) { + if (!enable) + return r; + goto err_compute; + } + } + } + } + } + + return 0; + +err_compute: + for (p--; p >= 0; p--) { + irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP + + (m * adev->gfx.mec.num_pipe_per_mec) + p; + amdgpu_irq_put(adev, &adev->gfx.eop_irq, irq_type); + } + for (m--; m >= 0; m--) { + for (p = adev->gfx.mec.num_pipe_per_mec - 1; p >= 0; p--) { + irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP + + (m * adev->gfx.mec.num_pipe_per_mec) + p; + amdgpu_irq_put(adev, &adev->gfx.eop_irq, irq_type); + } + } + for (xcc_id--; xcc_id >= 0; xcc_id--) { + for (m = adev->gfx.mec.num_mec - 1; m <= 0; m--) { + for (p = adev->gfx.mec.num_pipe_per_mec - 1; p >= 0; p--) { + irq_type = AMDGPU_CP_IRQ_COMPUTE_MEC1_PIPE0_EOP + + (m * adev->gfx.mec.num_pipe_per_mec) + p; + amdgpu_irq_put(adev, &adev->gfx.eop_irq, irq_type); + } + } + } + + return r; +} + static int gfx_v9_4_3_hw_init(struct amdgpu_ip_block *ip_block) { int r; @@ -2382,9 +2375,14 @@ static int gfx_v9_4_3_hw_init(struct amdgpu_ip_block *ip_block) r = amdgpu_irq_get(adev, &adev->gfx.bad_op_irq, 0); if (r) goto err_bad_op; + r = gfx_v9_4_3_set_userq_eop_interrupts(adev, true); + if (r) + goto err_bad_eop; return 0; +err_bad_eop: + amdgpu_irq_put(adev, &adev->gfx.bad_op_irq, 0); err_bad_op: amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); err_priv_inst: @@ -2467,6 +2465,7 @@ static int gfx_v9_4_3_hw_fini(struct amdgpu_ip_block *ip_block) amdgpu_irq_put(adev, &adev->gfx.bad_op_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_inst_irq, 0); amdgpu_irq_put(adev, &adev->gfx.priv_reg_irq, 0); + gfx_v9_4_3_set_userq_eop_interrupts(adev, false); num_xcc = NUM_XCC(adev->gfx.xcc_mask); for (i = 0; i < num_xcc; i++) { @@ -2612,8 +2611,24 @@ static int gfx_v9_4_3_early_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; - adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev), - AMDGPU_MAX_COMPUTE_RINGS); + switch (amdgpu_user_queue) { + case -1: + case 0: + default: + adev->gfx.disable_kq = false; + adev->gfx.disable_uq = true; + break; + case 2: + adev->gfx.disable_kq = true; + adev->gfx.disable_uq = true; + break; + } + + if (adev->gfx.disable_kq) + adev->gfx.num_compute_rings = 0; + else + adev->gfx.num_compute_rings = min(amdgpu_gfx_get_num_kcq(adev), + AMDGPU_MAX_COMPUTE_RINGS); gfx_v9_4_3_set_kiq_pm4_funcs(adev); gfx_v9_4_3_set_ring_funcs(adev); gfx_v9_4_3_set_irq_funcs(adev); @@ -2623,6 +2638,8 @@ static int gfx_v9_4_3_early_init(struct amdgpu_ip_block *ip_block) /* init rlcg reg access ctrl */ gfx_v9_4_3_init_rlcg_reg_access_ctrl(adev); + amdgpu_init_rlc_reg_funcs(adev); + return gfx_v9_4_3_init_microcode(adev); } @@ -2944,7 +2961,7 @@ static void gfx_v9_4_3_ring_emit_ib_compute(struct amdgpu_ring *ring, } amdgpu_ring_write(ring, PACKET3(PACKET3_INDIRECT_BUFFER, 2)); - BUG_ON(ib->gpu_addr & 0x3); /* Dword align */ + WARN_ON(ib->gpu_addr & 0x3); /* Dword align */ amdgpu_ring_write(ring, #ifdef __BIG_ENDIAN (2 << 0) | @@ -2978,9 +2995,9 @@ static void gfx_v9_4_3_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, * aligned if only send 32bit data low (discard data high) */ if (write64bit) - BUG_ON(addr & 0x7); + WARN_ON(addr & 0x7); else - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -3040,9 +3057,6 @@ static void gfx_v9_4_3_ring_emit_fence_kiq(struct amdgpu_ring *ring, u64 addr, { struct amdgpu_device *adev = ring->adev; - /* we only allocate 32bit for each seq wb address */ - BUG_ON(flags & AMDGPU_FENCE_FLAG_64BIT); - /* write fence seq to the "addr" */ amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3)); amdgpu_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) | @@ -3712,872 +3726,6 @@ static int gfx_v9_4_3_reset_kcq(struct amdgpu_ring *ring, return amdgpu_ring_reset_helper_end(ring, timedout_fence); } -enum amdgpu_gfx_cp_ras_mem_id { - AMDGPU_GFX_CP_MEM1 = 1, - AMDGPU_GFX_CP_MEM2, - AMDGPU_GFX_CP_MEM3, - AMDGPU_GFX_CP_MEM4, - AMDGPU_GFX_CP_MEM5, -}; - -enum amdgpu_gfx_gcea_ras_mem_id { - AMDGPU_GFX_GCEA_IOWR_CMDMEM = 4, - AMDGPU_GFX_GCEA_IORD_CMDMEM, - AMDGPU_GFX_GCEA_GMIWR_CMDMEM, - AMDGPU_GFX_GCEA_GMIRD_CMDMEM, - AMDGPU_GFX_GCEA_DRAMWR_CMDMEM, - AMDGPU_GFX_GCEA_DRAMRD_CMDMEM, - AMDGPU_GFX_GCEA_MAM_DMEM0, - AMDGPU_GFX_GCEA_MAM_DMEM1, - AMDGPU_GFX_GCEA_MAM_DMEM2, - AMDGPU_GFX_GCEA_MAM_DMEM3, - AMDGPU_GFX_GCEA_MAM_AMEM0, - AMDGPU_GFX_GCEA_MAM_AMEM1, - AMDGPU_GFX_GCEA_MAM_AMEM2, - AMDGPU_GFX_GCEA_MAM_AMEM3, - AMDGPU_GFX_GCEA_MAM_AFLUSH_BUFFER, - AMDGPU_GFX_GCEA_WRET_TAGMEM, - AMDGPU_GFX_GCEA_RRET_TAGMEM, - AMDGPU_GFX_GCEA_IOWR_DATAMEM, - AMDGPU_GFX_GCEA_GMIWR_DATAMEM, - AMDGPU_GFX_GCEA_DRAM_DATAMEM, -}; - -enum amdgpu_gfx_gc_cane_ras_mem_id { - AMDGPU_GFX_GC_CANE_MEM0 = 0, -}; - -enum amdgpu_gfx_gcutcl2_ras_mem_id { - AMDGPU_GFX_GCUTCL2_MEM2P512X95 = 160, -}; - -enum amdgpu_gfx_gds_ras_mem_id { - AMDGPU_GFX_GDS_MEM0 = 0, -}; - -enum amdgpu_gfx_lds_ras_mem_id { - AMDGPU_GFX_LDS_BANK0 = 0, - AMDGPU_GFX_LDS_BANK1, - AMDGPU_GFX_LDS_BANK2, - AMDGPU_GFX_LDS_BANK3, - AMDGPU_GFX_LDS_BANK4, - AMDGPU_GFX_LDS_BANK5, - AMDGPU_GFX_LDS_BANK6, - AMDGPU_GFX_LDS_BANK7, - AMDGPU_GFX_LDS_BANK8, - AMDGPU_GFX_LDS_BANK9, - AMDGPU_GFX_LDS_BANK10, - AMDGPU_GFX_LDS_BANK11, - AMDGPU_GFX_LDS_BANK12, - AMDGPU_GFX_LDS_BANK13, - AMDGPU_GFX_LDS_BANK14, - AMDGPU_GFX_LDS_BANK15, - AMDGPU_GFX_LDS_BANK16, - AMDGPU_GFX_LDS_BANK17, - AMDGPU_GFX_LDS_BANK18, - AMDGPU_GFX_LDS_BANK19, - AMDGPU_GFX_LDS_BANK20, - AMDGPU_GFX_LDS_BANK21, - AMDGPU_GFX_LDS_BANK22, - AMDGPU_GFX_LDS_BANK23, - AMDGPU_GFX_LDS_BANK24, - AMDGPU_GFX_LDS_BANK25, - AMDGPU_GFX_LDS_BANK26, - AMDGPU_GFX_LDS_BANK27, - AMDGPU_GFX_LDS_BANK28, - AMDGPU_GFX_LDS_BANK29, - AMDGPU_GFX_LDS_BANK30, - AMDGPU_GFX_LDS_BANK31, - AMDGPU_GFX_LDS_SP_BUFFER_A, - AMDGPU_GFX_LDS_SP_BUFFER_B, -}; - -enum amdgpu_gfx_rlc_ras_mem_id { - AMDGPU_GFX_RLC_GPMF32 = 1, - AMDGPU_GFX_RLC_RLCVF32, - AMDGPU_GFX_RLC_SCRATCH, - AMDGPU_GFX_RLC_SRM_ARAM, - AMDGPU_GFX_RLC_SRM_DRAM, - AMDGPU_GFX_RLC_TCTAG, - AMDGPU_GFX_RLC_SPM_SE, - AMDGPU_GFX_RLC_SPM_GRBMT, -}; - -enum amdgpu_gfx_sp_ras_mem_id { - AMDGPU_GFX_SP_SIMDID0 = 0, -}; - -enum amdgpu_gfx_spi_ras_mem_id { - AMDGPU_GFX_SPI_MEM0 = 0, - AMDGPU_GFX_SPI_MEM1, - AMDGPU_GFX_SPI_MEM2, - AMDGPU_GFX_SPI_MEM3, -}; - -enum amdgpu_gfx_sqc_ras_mem_id { - AMDGPU_GFX_SQC_INST_CACHE_A = 100, - AMDGPU_GFX_SQC_INST_CACHE_B = 101, - AMDGPU_GFX_SQC_INST_CACHE_TAG_A = 102, - AMDGPU_GFX_SQC_INST_CACHE_TAG_B = 103, - AMDGPU_GFX_SQC_INST_CACHE_MISS_FIFO_A = 104, - AMDGPU_GFX_SQC_INST_CACHE_MISS_FIFO_B = 105, - AMDGPU_GFX_SQC_INST_CACHE_GATCL1_MISS_FIFO_A = 106, - AMDGPU_GFX_SQC_INST_CACHE_GATCL1_MISS_FIFO_B = 107, - AMDGPU_GFX_SQC_DATA_CACHE_A = 200, - AMDGPU_GFX_SQC_DATA_CACHE_B = 201, - AMDGPU_GFX_SQC_DATA_CACHE_TAG_A = 202, - AMDGPU_GFX_SQC_DATA_CACHE_TAG_B = 203, - AMDGPU_GFX_SQC_DATA_CACHE_MISS_FIFO_A = 204, - AMDGPU_GFX_SQC_DATA_CACHE_MISS_FIFO_B = 205, - AMDGPU_GFX_SQC_DATA_CACHE_HIT_FIFO_A = 206, - AMDGPU_GFX_SQC_DATA_CACHE_HIT_FIFO_B = 207, - AMDGPU_GFX_SQC_DIRTY_BIT_A = 208, - AMDGPU_GFX_SQC_DIRTY_BIT_B = 209, - AMDGPU_GFX_SQC_WRITE_DATA_BUFFER_CU0 = 210, - AMDGPU_GFX_SQC_WRITE_DATA_BUFFER_CU1 = 211, - AMDGPU_GFX_SQC_UTCL1_MISS_LFIFO_DATA_CACHE_A = 212, - AMDGPU_GFX_SQC_UTCL1_MISS_LFIFO_DATA_CACHE_B = 213, - AMDGPU_GFX_SQC_UTCL1_MISS_LFIFO_INST_CACHE = 108, -}; - -enum amdgpu_gfx_sq_ras_mem_id { - AMDGPU_GFX_SQ_SGPR_MEM0 = 0, - AMDGPU_GFX_SQ_SGPR_MEM1, - AMDGPU_GFX_SQ_SGPR_MEM2, - AMDGPU_GFX_SQ_SGPR_MEM3, -}; - -enum amdgpu_gfx_ta_ras_mem_id { - AMDGPU_GFX_TA_FS_AFIFO_RAM_LO = 1, - AMDGPU_GFX_TA_FS_AFIFO_RAM_HI, - AMDGPU_GFX_TA_FS_CFIFO_RAM, - AMDGPU_GFX_TA_FSX_LFIFO, - AMDGPU_GFX_TA_FS_DFIFO_RAM, -}; - -enum amdgpu_gfx_tcc_ras_mem_id { - AMDGPU_GFX_TCC_MEM1 = 1, -}; - -enum amdgpu_gfx_tca_ras_mem_id { - AMDGPU_GFX_TCA_MEM1 = 1, -}; - -enum amdgpu_gfx_tci_ras_mem_id { - AMDGPU_GFX_TCIW_MEM = 1, -}; - -enum amdgpu_gfx_tcp_ras_mem_id { - AMDGPU_GFX_TCP_LFIFO0 = 1, - AMDGPU_GFX_TCP_SET0BANK0_RAM, - AMDGPU_GFX_TCP_SET0BANK1_RAM, - AMDGPU_GFX_TCP_SET0BANK2_RAM, - AMDGPU_GFX_TCP_SET0BANK3_RAM, - AMDGPU_GFX_TCP_SET1BANK0_RAM, - AMDGPU_GFX_TCP_SET1BANK1_RAM, - AMDGPU_GFX_TCP_SET1BANK2_RAM, - AMDGPU_GFX_TCP_SET1BANK3_RAM, - AMDGPU_GFX_TCP_SET2BANK0_RAM, - AMDGPU_GFX_TCP_SET2BANK1_RAM, - AMDGPU_GFX_TCP_SET2BANK2_RAM, - AMDGPU_GFX_TCP_SET2BANK3_RAM, - AMDGPU_GFX_TCP_SET3BANK0_RAM, - AMDGPU_GFX_TCP_SET3BANK1_RAM, - AMDGPU_GFX_TCP_SET3BANK2_RAM, - AMDGPU_GFX_TCP_SET3BANK3_RAM, - AMDGPU_GFX_TCP_VM_FIFO, - AMDGPU_GFX_TCP_DB_TAGRAM0, - AMDGPU_GFX_TCP_DB_TAGRAM1, - AMDGPU_GFX_TCP_DB_TAGRAM2, - AMDGPU_GFX_TCP_DB_TAGRAM3, - AMDGPU_GFX_TCP_UTCL1_LFIFO_PROBE0, - AMDGPU_GFX_TCP_UTCL1_LFIFO_PROBE1, - AMDGPU_GFX_TCP_CMD_FIFO, -}; - -enum amdgpu_gfx_td_ras_mem_id { - AMDGPU_GFX_TD_UTD_CS_FIFO_MEM = 1, - AMDGPU_GFX_TD_UTD_SS_FIFO_LO_MEM, - AMDGPU_GFX_TD_UTD_SS_FIFO_HI_MEM, -}; - -enum amdgpu_gfx_tcx_ras_mem_id { - AMDGPU_GFX_TCX_FIFOD0 = 0, - AMDGPU_GFX_TCX_FIFOD1, - AMDGPU_GFX_TCX_FIFOD2, - AMDGPU_GFX_TCX_FIFOD3, - AMDGPU_GFX_TCX_FIFOD4, - AMDGPU_GFX_TCX_FIFOD5, - AMDGPU_GFX_TCX_FIFOD6, - AMDGPU_GFX_TCX_FIFOD7, - AMDGPU_GFX_TCX_FIFOB0, - AMDGPU_GFX_TCX_FIFOB1, - AMDGPU_GFX_TCX_FIFOB2, - AMDGPU_GFX_TCX_FIFOB3, - AMDGPU_GFX_TCX_FIFOB4, - AMDGPU_GFX_TCX_FIFOB5, - AMDGPU_GFX_TCX_FIFOB6, - AMDGPU_GFX_TCX_FIFOB7, - AMDGPU_GFX_TCX_FIFOA0, - AMDGPU_GFX_TCX_FIFOA1, - AMDGPU_GFX_TCX_FIFOA2, - AMDGPU_GFX_TCX_FIFOA3, - AMDGPU_GFX_TCX_FIFOA4, - AMDGPU_GFX_TCX_FIFOA5, - AMDGPU_GFX_TCX_FIFOA6, - AMDGPU_GFX_TCX_FIFOA7, - AMDGPU_GFX_TCX_CFIFO0, - AMDGPU_GFX_TCX_CFIFO1, - AMDGPU_GFX_TCX_CFIFO2, - AMDGPU_GFX_TCX_CFIFO3, - AMDGPU_GFX_TCX_CFIFO4, - AMDGPU_GFX_TCX_CFIFO5, - AMDGPU_GFX_TCX_CFIFO6, - AMDGPU_GFX_TCX_CFIFO7, - AMDGPU_GFX_TCX_FIFO_ACKB0, - AMDGPU_GFX_TCX_FIFO_ACKB1, - AMDGPU_GFX_TCX_FIFO_ACKB2, - AMDGPU_GFX_TCX_FIFO_ACKB3, - AMDGPU_GFX_TCX_FIFO_ACKB4, - AMDGPU_GFX_TCX_FIFO_ACKB5, - AMDGPU_GFX_TCX_FIFO_ACKB6, - AMDGPU_GFX_TCX_FIFO_ACKB7, - AMDGPU_GFX_TCX_FIFO_ACKD0, - AMDGPU_GFX_TCX_FIFO_ACKD1, - AMDGPU_GFX_TCX_FIFO_ACKD2, - AMDGPU_GFX_TCX_FIFO_ACKD3, - AMDGPU_GFX_TCX_FIFO_ACKD4, - AMDGPU_GFX_TCX_FIFO_ACKD5, - AMDGPU_GFX_TCX_FIFO_ACKD6, - AMDGPU_GFX_TCX_FIFO_ACKD7, - AMDGPU_GFX_TCX_DST_FIFOA0, - AMDGPU_GFX_TCX_DST_FIFOA1, - AMDGPU_GFX_TCX_DST_FIFOA2, - AMDGPU_GFX_TCX_DST_FIFOA3, - AMDGPU_GFX_TCX_DST_FIFOA4, - AMDGPU_GFX_TCX_DST_FIFOA5, - AMDGPU_GFX_TCX_DST_FIFOA6, - AMDGPU_GFX_TCX_DST_FIFOA7, - AMDGPU_GFX_TCX_DST_FIFOB0, - AMDGPU_GFX_TCX_DST_FIFOB1, - AMDGPU_GFX_TCX_DST_FIFOB2, - AMDGPU_GFX_TCX_DST_FIFOB3, - AMDGPU_GFX_TCX_DST_FIFOB4, - AMDGPU_GFX_TCX_DST_FIFOB5, - AMDGPU_GFX_TCX_DST_FIFOB6, - AMDGPU_GFX_TCX_DST_FIFOB7, - AMDGPU_GFX_TCX_DST_FIFOD0, - AMDGPU_GFX_TCX_DST_FIFOD1, - AMDGPU_GFX_TCX_DST_FIFOD2, - AMDGPU_GFX_TCX_DST_FIFOD3, - AMDGPU_GFX_TCX_DST_FIFOD4, - AMDGPU_GFX_TCX_DST_FIFOD5, - AMDGPU_GFX_TCX_DST_FIFOD6, - AMDGPU_GFX_TCX_DST_FIFOD7, - AMDGPU_GFX_TCX_DST_FIFO_ACKB0, - AMDGPU_GFX_TCX_DST_FIFO_ACKB1, - AMDGPU_GFX_TCX_DST_FIFO_ACKB2, - AMDGPU_GFX_TCX_DST_FIFO_ACKB3, - AMDGPU_GFX_TCX_DST_FIFO_ACKB4, - AMDGPU_GFX_TCX_DST_FIFO_ACKB5, - AMDGPU_GFX_TCX_DST_FIFO_ACKB6, - AMDGPU_GFX_TCX_DST_FIFO_ACKB7, - AMDGPU_GFX_TCX_DST_FIFO_ACKD0, - AMDGPU_GFX_TCX_DST_FIFO_ACKD1, - AMDGPU_GFX_TCX_DST_FIFO_ACKD2, - AMDGPU_GFX_TCX_DST_FIFO_ACKD3, - AMDGPU_GFX_TCX_DST_FIFO_ACKD4, - AMDGPU_GFX_TCX_DST_FIFO_ACKD5, - AMDGPU_GFX_TCX_DST_FIFO_ACKD6, - AMDGPU_GFX_TCX_DST_FIFO_ACKD7, -}; - -enum amdgpu_gfx_atc_l2_ras_mem_id { - AMDGPU_GFX_ATC_L2_MEM0 = 0, -}; - -enum amdgpu_gfx_utcl2_ras_mem_id { - AMDGPU_GFX_UTCL2_MEM0 = 0, -}; - -enum amdgpu_gfx_vml2_ras_mem_id { - AMDGPU_GFX_VML2_MEM0 = 0, -}; - -enum amdgpu_gfx_vml2_walker_ras_mem_id { - AMDGPU_GFX_VML2_WALKER_MEM0 = 0, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_cp_mem_list[] = { - {AMDGPU_GFX_CP_MEM1, "CP_MEM1"}, - {AMDGPU_GFX_CP_MEM2, "CP_MEM2"}, - {AMDGPU_GFX_CP_MEM3, "CP_MEM3"}, - {AMDGPU_GFX_CP_MEM4, "CP_MEM4"}, - {AMDGPU_GFX_CP_MEM5, "CP_MEM5"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_gcea_mem_list[] = { - {AMDGPU_GFX_GCEA_IOWR_CMDMEM, "GCEA_IOWR_CMDMEM"}, - {AMDGPU_GFX_GCEA_IORD_CMDMEM, "GCEA_IORD_CMDMEM"}, - {AMDGPU_GFX_GCEA_GMIWR_CMDMEM, "GCEA_GMIWR_CMDMEM"}, - {AMDGPU_GFX_GCEA_GMIRD_CMDMEM, "GCEA_GMIRD_CMDMEM"}, - {AMDGPU_GFX_GCEA_DRAMWR_CMDMEM, "GCEA_DRAMWR_CMDMEM"}, - {AMDGPU_GFX_GCEA_DRAMRD_CMDMEM, "GCEA_DRAMRD_CMDMEM"}, - {AMDGPU_GFX_GCEA_MAM_DMEM0, "GCEA_MAM_DMEM0"}, - {AMDGPU_GFX_GCEA_MAM_DMEM1, "GCEA_MAM_DMEM1"}, - {AMDGPU_GFX_GCEA_MAM_DMEM2, "GCEA_MAM_DMEM2"}, - {AMDGPU_GFX_GCEA_MAM_DMEM3, "GCEA_MAM_DMEM3"}, - {AMDGPU_GFX_GCEA_MAM_AMEM0, "GCEA_MAM_AMEM0"}, - {AMDGPU_GFX_GCEA_MAM_AMEM1, "GCEA_MAM_AMEM1"}, - {AMDGPU_GFX_GCEA_MAM_AMEM2, "GCEA_MAM_AMEM2"}, - {AMDGPU_GFX_GCEA_MAM_AMEM3, "GCEA_MAM_AMEM3"}, - {AMDGPU_GFX_GCEA_MAM_AFLUSH_BUFFER, "GCEA_MAM_AFLUSH_BUFFER"}, - {AMDGPU_GFX_GCEA_WRET_TAGMEM, "GCEA_WRET_TAGMEM"}, - {AMDGPU_GFX_GCEA_RRET_TAGMEM, "GCEA_RRET_TAGMEM"}, - {AMDGPU_GFX_GCEA_IOWR_DATAMEM, "GCEA_IOWR_DATAMEM"}, - {AMDGPU_GFX_GCEA_GMIWR_DATAMEM, "GCEA_GMIWR_DATAMEM"}, - {AMDGPU_GFX_GCEA_DRAM_DATAMEM, "GCEA_DRAM_DATAMEM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_gc_cane_mem_list[] = { - {AMDGPU_GFX_GC_CANE_MEM0, "GC_CANE_MEM0"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_gcutcl2_mem_list[] = { - {AMDGPU_GFX_GCUTCL2_MEM2P512X95, "GCUTCL2_MEM2P512X95"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_gds_mem_list[] = { - {AMDGPU_GFX_GDS_MEM0, "GDS_MEM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_lds_mem_list[] = { - {AMDGPU_GFX_LDS_BANK0, "LDS_BANK0"}, - {AMDGPU_GFX_LDS_BANK1, "LDS_BANK1"}, - {AMDGPU_GFX_LDS_BANK2, "LDS_BANK2"}, - {AMDGPU_GFX_LDS_BANK3, "LDS_BANK3"}, - {AMDGPU_GFX_LDS_BANK4, "LDS_BANK4"}, - {AMDGPU_GFX_LDS_BANK5, "LDS_BANK5"}, - {AMDGPU_GFX_LDS_BANK6, "LDS_BANK6"}, - {AMDGPU_GFX_LDS_BANK7, "LDS_BANK7"}, - {AMDGPU_GFX_LDS_BANK8, "LDS_BANK8"}, - {AMDGPU_GFX_LDS_BANK9, "LDS_BANK9"}, - {AMDGPU_GFX_LDS_BANK10, "LDS_BANK10"}, - {AMDGPU_GFX_LDS_BANK11, "LDS_BANK11"}, - {AMDGPU_GFX_LDS_BANK12, "LDS_BANK12"}, - {AMDGPU_GFX_LDS_BANK13, "LDS_BANK13"}, - {AMDGPU_GFX_LDS_BANK14, "LDS_BANK14"}, - {AMDGPU_GFX_LDS_BANK15, "LDS_BANK15"}, - {AMDGPU_GFX_LDS_BANK16, "LDS_BANK16"}, - {AMDGPU_GFX_LDS_BANK17, "LDS_BANK17"}, - {AMDGPU_GFX_LDS_BANK18, "LDS_BANK18"}, - {AMDGPU_GFX_LDS_BANK19, "LDS_BANK19"}, - {AMDGPU_GFX_LDS_BANK20, "LDS_BANK20"}, - {AMDGPU_GFX_LDS_BANK21, "LDS_BANK21"}, - {AMDGPU_GFX_LDS_BANK22, "LDS_BANK22"}, - {AMDGPU_GFX_LDS_BANK23, "LDS_BANK23"}, - {AMDGPU_GFX_LDS_BANK24, "LDS_BANK24"}, - {AMDGPU_GFX_LDS_BANK25, "LDS_BANK25"}, - {AMDGPU_GFX_LDS_BANK26, "LDS_BANK26"}, - {AMDGPU_GFX_LDS_BANK27, "LDS_BANK27"}, - {AMDGPU_GFX_LDS_BANK28, "LDS_BANK28"}, - {AMDGPU_GFX_LDS_BANK29, "LDS_BANK29"}, - {AMDGPU_GFX_LDS_BANK30, "LDS_BANK30"}, - {AMDGPU_GFX_LDS_BANK31, "LDS_BANK31"}, - {AMDGPU_GFX_LDS_SP_BUFFER_A, "LDS_SP_BUFFER_A"}, - {AMDGPU_GFX_LDS_SP_BUFFER_B, "LDS_SP_BUFFER_B"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_rlc_mem_list[] = { - {AMDGPU_GFX_RLC_GPMF32, "RLC_GPMF32"}, - {AMDGPU_GFX_RLC_RLCVF32, "RLC_RLCVF32"}, - {AMDGPU_GFX_RLC_SCRATCH, "RLC_SCRATCH"}, - {AMDGPU_GFX_RLC_SRM_ARAM, "RLC_SRM_ARAM"}, - {AMDGPU_GFX_RLC_SRM_DRAM, "RLC_SRM_DRAM"}, - {AMDGPU_GFX_RLC_TCTAG, "RLC_TCTAG"}, - {AMDGPU_GFX_RLC_SPM_SE, "RLC_SPM_SE"}, - {AMDGPU_GFX_RLC_SPM_GRBMT, "RLC_SPM_GRBMT"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_sp_mem_list[] = { - {AMDGPU_GFX_SP_SIMDID0, "SP_SIMDID0"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_spi_mem_list[] = { - {AMDGPU_GFX_SPI_MEM0, "SPI_MEM0"}, - {AMDGPU_GFX_SPI_MEM1, "SPI_MEM1"}, - {AMDGPU_GFX_SPI_MEM2, "SPI_MEM2"}, - {AMDGPU_GFX_SPI_MEM3, "SPI_MEM3"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_sqc_mem_list[] = { - {AMDGPU_GFX_SQC_INST_CACHE_A, "SQC_INST_CACHE_A"}, - {AMDGPU_GFX_SQC_INST_CACHE_B, "SQC_INST_CACHE_B"}, - {AMDGPU_GFX_SQC_INST_CACHE_TAG_A, "SQC_INST_CACHE_TAG_A"}, - {AMDGPU_GFX_SQC_INST_CACHE_TAG_B, "SQC_INST_CACHE_TAG_B"}, - {AMDGPU_GFX_SQC_INST_CACHE_MISS_FIFO_A, "SQC_INST_CACHE_MISS_FIFO_A"}, - {AMDGPU_GFX_SQC_INST_CACHE_MISS_FIFO_B, "SQC_INST_CACHE_MISS_FIFO_B"}, - {AMDGPU_GFX_SQC_INST_CACHE_GATCL1_MISS_FIFO_A, "SQC_INST_CACHE_GATCL1_MISS_FIFO_A"}, - {AMDGPU_GFX_SQC_INST_CACHE_GATCL1_MISS_FIFO_B, "SQC_INST_CACHE_GATCL1_MISS_FIFO_B"}, - {AMDGPU_GFX_SQC_DATA_CACHE_A, "SQC_DATA_CACHE_A"}, - {AMDGPU_GFX_SQC_DATA_CACHE_B, "SQC_DATA_CACHE_B"}, - {AMDGPU_GFX_SQC_DATA_CACHE_TAG_A, "SQC_DATA_CACHE_TAG_A"}, - {AMDGPU_GFX_SQC_DATA_CACHE_TAG_B, "SQC_DATA_CACHE_TAG_B"}, - {AMDGPU_GFX_SQC_DATA_CACHE_MISS_FIFO_A, "SQC_DATA_CACHE_MISS_FIFO_A"}, - {AMDGPU_GFX_SQC_DATA_CACHE_MISS_FIFO_B, "SQC_DATA_CACHE_MISS_FIFO_B"}, - {AMDGPU_GFX_SQC_DATA_CACHE_HIT_FIFO_A, "SQC_DATA_CACHE_HIT_FIFO_A"}, - {AMDGPU_GFX_SQC_DATA_CACHE_HIT_FIFO_B, "SQC_DATA_CACHE_HIT_FIFO_B"}, - {AMDGPU_GFX_SQC_DIRTY_BIT_A, "SQC_DIRTY_BIT_A"}, - {AMDGPU_GFX_SQC_DIRTY_BIT_B, "SQC_DIRTY_BIT_B"}, - {AMDGPU_GFX_SQC_WRITE_DATA_BUFFER_CU0, "SQC_WRITE_DATA_BUFFER_CU0"}, - {AMDGPU_GFX_SQC_WRITE_DATA_BUFFER_CU1, "SQC_WRITE_DATA_BUFFER_CU1"}, - {AMDGPU_GFX_SQC_UTCL1_MISS_LFIFO_DATA_CACHE_A, "SQC_UTCL1_MISS_LFIFO_DATA_CACHE_A"}, - {AMDGPU_GFX_SQC_UTCL1_MISS_LFIFO_DATA_CACHE_B, "SQC_UTCL1_MISS_LFIFO_DATA_CACHE_B"}, - {AMDGPU_GFX_SQC_UTCL1_MISS_LFIFO_INST_CACHE, "SQC_UTCL1_MISS_LFIFO_INST_CACHE"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_sq_mem_list[] = { - {AMDGPU_GFX_SQ_SGPR_MEM0, "SQ_SGPR_MEM0"}, - {AMDGPU_GFX_SQ_SGPR_MEM1, "SQ_SGPR_MEM1"}, - {AMDGPU_GFX_SQ_SGPR_MEM2, "SQ_SGPR_MEM2"}, - {AMDGPU_GFX_SQ_SGPR_MEM3, "SQ_SGPR_MEM3"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_ta_mem_list[] = { - {AMDGPU_GFX_TA_FS_AFIFO_RAM_LO, "TA_FS_AFIFO_RAM_LO"}, - {AMDGPU_GFX_TA_FS_AFIFO_RAM_HI, "TA_FS_AFIFO_RAM_HI"}, - {AMDGPU_GFX_TA_FS_CFIFO_RAM, "TA_FS_CFIFO_RAM"}, - {AMDGPU_GFX_TA_FSX_LFIFO, "TA_FSX_LFIFO"}, - {AMDGPU_GFX_TA_FS_DFIFO_RAM, "TA_FS_DFIFO_RAM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_tcc_mem_list[] = { - {AMDGPU_GFX_TCC_MEM1, "TCC_MEM1"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_tca_mem_list[] = { - {AMDGPU_GFX_TCA_MEM1, "TCA_MEM1"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_tci_mem_list[] = { - {AMDGPU_GFX_TCIW_MEM, "TCIW_MEM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_tcp_mem_list[] = { - {AMDGPU_GFX_TCP_LFIFO0, "TCP_LFIFO0"}, - {AMDGPU_GFX_TCP_SET0BANK0_RAM, "TCP_SET0BANK0_RAM"}, - {AMDGPU_GFX_TCP_SET0BANK1_RAM, "TCP_SET0BANK1_RAM"}, - {AMDGPU_GFX_TCP_SET0BANK2_RAM, "TCP_SET0BANK2_RAM"}, - {AMDGPU_GFX_TCP_SET0BANK3_RAM, "TCP_SET0BANK3_RAM"}, - {AMDGPU_GFX_TCP_SET1BANK0_RAM, "TCP_SET1BANK0_RAM"}, - {AMDGPU_GFX_TCP_SET1BANK1_RAM, "TCP_SET1BANK1_RAM"}, - {AMDGPU_GFX_TCP_SET1BANK2_RAM, "TCP_SET1BANK2_RAM"}, - {AMDGPU_GFX_TCP_SET1BANK3_RAM, "TCP_SET1BANK3_RAM"}, - {AMDGPU_GFX_TCP_SET2BANK0_RAM, "TCP_SET2BANK0_RAM"}, - {AMDGPU_GFX_TCP_SET2BANK1_RAM, "TCP_SET2BANK1_RAM"}, - {AMDGPU_GFX_TCP_SET2BANK2_RAM, "TCP_SET2BANK2_RAM"}, - {AMDGPU_GFX_TCP_SET2BANK3_RAM, "TCP_SET2BANK3_RAM"}, - {AMDGPU_GFX_TCP_SET3BANK0_RAM, "TCP_SET3BANK0_RAM"}, - {AMDGPU_GFX_TCP_SET3BANK1_RAM, "TCP_SET3BANK1_RAM"}, - {AMDGPU_GFX_TCP_SET3BANK2_RAM, "TCP_SET3BANK2_RAM"}, - {AMDGPU_GFX_TCP_SET3BANK3_RAM, "TCP_SET3BANK3_RAM"}, - {AMDGPU_GFX_TCP_VM_FIFO, "TCP_VM_FIFO"}, - {AMDGPU_GFX_TCP_DB_TAGRAM0, "TCP_DB_TAGRAM0"}, - {AMDGPU_GFX_TCP_DB_TAGRAM1, "TCP_DB_TAGRAM1"}, - {AMDGPU_GFX_TCP_DB_TAGRAM2, "TCP_DB_TAGRAM2"}, - {AMDGPU_GFX_TCP_DB_TAGRAM3, "TCP_DB_TAGRAM3"}, - {AMDGPU_GFX_TCP_UTCL1_LFIFO_PROBE0, "TCP_UTCL1_LFIFO_PROBE0"}, - {AMDGPU_GFX_TCP_UTCL1_LFIFO_PROBE1, "TCP_UTCL1_LFIFO_PROBE1"}, - {AMDGPU_GFX_TCP_CMD_FIFO, "TCP_CMD_FIFO"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_td_mem_list[] = { - {AMDGPU_GFX_TD_UTD_CS_FIFO_MEM, "TD_UTD_CS_FIFO_MEM"}, - {AMDGPU_GFX_TD_UTD_SS_FIFO_LO_MEM, "TD_UTD_SS_FIFO_LO_MEM"}, - {AMDGPU_GFX_TD_UTD_SS_FIFO_HI_MEM, "TD_UTD_SS_FIFO_HI_MEM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_tcx_mem_list[] = { - {AMDGPU_GFX_TCX_FIFOD0, "TCX_FIFOD0"}, - {AMDGPU_GFX_TCX_FIFOD1, "TCX_FIFOD1"}, - {AMDGPU_GFX_TCX_FIFOD2, "TCX_FIFOD2"}, - {AMDGPU_GFX_TCX_FIFOD3, "TCX_FIFOD3"}, - {AMDGPU_GFX_TCX_FIFOD4, "TCX_FIFOD4"}, - {AMDGPU_GFX_TCX_FIFOD5, "TCX_FIFOD5"}, - {AMDGPU_GFX_TCX_FIFOD6, "TCX_FIFOD6"}, - {AMDGPU_GFX_TCX_FIFOD7, "TCX_FIFOD7"}, - {AMDGPU_GFX_TCX_FIFOB0, "TCX_FIFOB0"}, - {AMDGPU_GFX_TCX_FIFOB1, "TCX_FIFOB1"}, - {AMDGPU_GFX_TCX_FIFOB2, "TCX_FIFOB2"}, - {AMDGPU_GFX_TCX_FIFOB3, "TCX_FIFOB3"}, - {AMDGPU_GFX_TCX_FIFOB4, "TCX_FIFOB4"}, - {AMDGPU_GFX_TCX_FIFOB5, "TCX_FIFOB5"}, - {AMDGPU_GFX_TCX_FIFOB6, "TCX_FIFOB6"}, - {AMDGPU_GFX_TCX_FIFOB7, "TCX_FIFOB7"}, - {AMDGPU_GFX_TCX_FIFOA0, "TCX_FIFOA0"}, - {AMDGPU_GFX_TCX_FIFOA1, "TCX_FIFOA1"}, - {AMDGPU_GFX_TCX_FIFOA2, "TCX_FIFOA2"}, - {AMDGPU_GFX_TCX_FIFOA3, "TCX_FIFOA3"}, - {AMDGPU_GFX_TCX_FIFOA4, "TCX_FIFOA4"}, - {AMDGPU_GFX_TCX_FIFOA5, "TCX_FIFOA5"}, - {AMDGPU_GFX_TCX_FIFOA6, "TCX_FIFOA6"}, - {AMDGPU_GFX_TCX_FIFOA7, "TCX_FIFOA7"}, - {AMDGPU_GFX_TCX_CFIFO0, "TCX_CFIFO0"}, - {AMDGPU_GFX_TCX_CFIFO1, "TCX_CFIFO1"}, - {AMDGPU_GFX_TCX_CFIFO2, "TCX_CFIFO2"}, - {AMDGPU_GFX_TCX_CFIFO3, "TCX_CFIFO3"}, - {AMDGPU_GFX_TCX_CFIFO4, "TCX_CFIFO4"}, - {AMDGPU_GFX_TCX_CFIFO5, "TCX_CFIFO5"}, - {AMDGPU_GFX_TCX_CFIFO6, "TCX_CFIFO6"}, - {AMDGPU_GFX_TCX_CFIFO7, "TCX_CFIFO7"}, - {AMDGPU_GFX_TCX_FIFO_ACKB0, "TCX_FIFO_ACKB0"}, - {AMDGPU_GFX_TCX_FIFO_ACKB1, "TCX_FIFO_ACKB1"}, - {AMDGPU_GFX_TCX_FIFO_ACKB2, "TCX_FIFO_ACKB2"}, - {AMDGPU_GFX_TCX_FIFO_ACKB3, "TCX_FIFO_ACKB3"}, - {AMDGPU_GFX_TCX_FIFO_ACKB4, "TCX_FIFO_ACKB4"}, - {AMDGPU_GFX_TCX_FIFO_ACKB5, "TCX_FIFO_ACKB5"}, - {AMDGPU_GFX_TCX_FIFO_ACKB6, "TCX_FIFO_ACKB6"}, - {AMDGPU_GFX_TCX_FIFO_ACKB7, "TCX_FIFO_ACKB7"}, - {AMDGPU_GFX_TCX_FIFO_ACKD0, "TCX_FIFO_ACKD0"}, - {AMDGPU_GFX_TCX_FIFO_ACKD1, "TCX_FIFO_ACKD1"}, - {AMDGPU_GFX_TCX_FIFO_ACKD2, "TCX_FIFO_ACKD2"}, - {AMDGPU_GFX_TCX_FIFO_ACKD3, "TCX_FIFO_ACKD3"}, - {AMDGPU_GFX_TCX_FIFO_ACKD4, "TCX_FIFO_ACKD4"}, - {AMDGPU_GFX_TCX_FIFO_ACKD5, "TCX_FIFO_ACKD5"}, - {AMDGPU_GFX_TCX_FIFO_ACKD6, "TCX_FIFO_ACKD6"}, - {AMDGPU_GFX_TCX_FIFO_ACKD7, "TCX_FIFO_ACKD7"}, - {AMDGPU_GFX_TCX_DST_FIFOA0, "TCX_DST_FIFOA0"}, - {AMDGPU_GFX_TCX_DST_FIFOA1, "TCX_DST_FIFOA1"}, - {AMDGPU_GFX_TCX_DST_FIFOA2, "TCX_DST_FIFOA2"}, - {AMDGPU_GFX_TCX_DST_FIFOA3, "TCX_DST_FIFOA3"}, - {AMDGPU_GFX_TCX_DST_FIFOA4, "TCX_DST_FIFOA4"}, - {AMDGPU_GFX_TCX_DST_FIFOA5, "TCX_DST_FIFOA5"}, - {AMDGPU_GFX_TCX_DST_FIFOA6, "TCX_DST_FIFOA6"}, - {AMDGPU_GFX_TCX_DST_FIFOA7, "TCX_DST_FIFOA7"}, - {AMDGPU_GFX_TCX_DST_FIFOB0, "TCX_DST_FIFOB0"}, - {AMDGPU_GFX_TCX_DST_FIFOB1, "TCX_DST_FIFOB1"}, - {AMDGPU_GFX_TCX_DST_FIFOB2, "TCX_DST_FIFOB2"}, - {AMDGPU_GFX_TCX_DST_FIFOB3, "TCX_DST_FIFOB3"}, - {AMDGPU_GFX_TCX_DST_FIFOB4, "TCX_DST_FIFOB4"}, - {AMDGPU_GFX_TCX_DST_FIFOB5, "TCX_DST_FIFOB5"}, - {AMDGPU_GFX_TCX_DST_FIFOB6, "TCX_DST_FIFOB6"}, - {AMDGPU_GFX_TCX_DST_FIFOB7, "TCX_DST_FIFOB7"}, - {AMDGPU_GFX_TCX_DST_FIFOD0, "TCX_DST_FIFOD0"}, - {AMDGPU_GFX_TCX_DST_FIFOD1, "TCX_DST_FIFOD1"}, - {AMDGPU_GFX_TCX_DST_FIFOD2, "TCX_DST_FIFOD2"}, - {AMDGPU_GFX_TCX_DST_FIFOD3, "TCX_DST_FIFOD3"}, - {AMDGPU_GFX_TCX_DST_FIFOD4, "TCX_DST_FIFOD4"}, - {AMDGPU_GFX_TCX_DST_FIFOD5, "TCX_DST_FIFOD5"}, - {AMDGPU_GFX_TCX_DST_FIFOD6, "TCX_DST_FIFOD6"}, - {AMDGPU_GFX_TCX_DST_FIFOD7, "TCX_DST_FIFOD7"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB0, "TCX_DST_FIFO_ACKB0"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB1, "TCX_DST_FIFO_ACKB1"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB2, "TCX_DST_FIFO_ACKB2"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB3, "TCX_DST_FIFO_ACKB3"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB4, "TCX_DST_FIFO_ACKB4"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB5, "TCX_DST_FIFO_ACKB5"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB6, "TCX_DST_FIFO_ACKB6"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKB7, "TCX_DST_FIFO_ACKB7"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD0, "TCX_DST_FIFO_ACKD0"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD1, "TCX_DST_FIFO_ACKD1"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD2, "TCX_DST_FIFO_ACKD2"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD3, "TCX_DST_FIFO_ACKD3"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD4, "TCX_DST_FIFO_ACKD4"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD5, "TCX_DST_FIFO_ACKD5"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD6, "TCX_DST_FIFO_ACKD6"}, - {AMDGPU_GFX_TCX_DST_FIFO_ACKD7, "TCX_DST_FIFO_ACKD7"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_atc_l2_mem_list[] = { - {AMDGPU_GFX_ATC_L2_MEM, "ATC_L2_MEM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_utcl2_mem_list[] = { - {AMDGPU_GFX_UTCL2_MEM, "UTCL2_MEM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_vml2_mem_list[] = { - {AMDGPU_GFX_VML2_MEM, "VML2_MEM"}, -}; - -static const struct amdgpu_ras_memory_id_entry gfx_v9_4_3_ras_vml2_walker_mem_list[] = { - {AMDGPU_GFX_VML2_WALKER_MEM, "VML2_WALKER_MEM"}, -}; - -static const struct amdgpu_gfx_ras_mem_id_entry gfx_v9_4_3_ras_mem_list_array[AMDGPU_GFX_MEM_TYPE_NUM] = { - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_cp_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_gcea_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_gc_cane_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_gcutcl2_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_gds_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_lds_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_rlc_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_sp_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_spi_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_sqc_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_sq_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_ta_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_tcc_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_tca_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_tci_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_tcp_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_td_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_tcx_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_atc_l2_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_utcl2_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_vml2_mem_list) - AMDGPU_GFX_MEMID_ENT(gfx_v9_4_3_ras_vml2_walker_mem_list) -}; - -static const struct amdgpu_gfx_ras_reg_entry gfx_v9_4_3_ce_reg_list[] = { - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regRLC_CE_ERR_STATUS_LOW, regRLC_CE_ERR_STATUS_HIGH), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "RLC"}, - AMDGPU_GFX_RLC_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regCPC_CE_ERR_STATUS_LO, regCPC_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CPC"}, - AMDGPU_GFX_CP_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regCPF_CE_ERR_STATUS_LO, regCPF_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CPF"}, - AMDGPU_GFX_CP_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regCPG_CE_ERR_STATUS_LO, regCPG_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CPG"}, - AMDGPU_GFX_CP_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regGDS_CE_ERR_STATUS_LO, regGDS_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "GDS"}, - AMDGPU_GFX_GDS_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regGC_CANE_CE_ERR_STATUS_LO, regGC_CANE_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CANE"}, - AMDGPU_GFX_GC_CANE_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSPI_CE_ERR_STATUS_LO, regSPI_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SPI"}, - AMDGPU_GFX_SPI_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSP0_CE_ERR_STATUS_LO, regSP0_CE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SP0"}, - AMDGPU_GFX_SP_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSP1_CE_ERR_STATUS_LO, regSP1_CE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SP1"}, - AMDGPU_GFX_SP_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSQ_CE_ERR_STATUS_LO, regSQ_CE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SQ"}, - AMDGPU_GFX_SQ_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSQC_CE_EDC_LO, regSQC_CE_EDC_HI), - 5, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SQC"}, - AMDGPU_GFX_SQC_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCX_CE_ERR_STATUS_LO, regTCX_CE_ERR_STATUS_HI), - 2, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCX"}, - AMDGPU_GFX_TCX_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCC_CE_ERR_STATUS_LO, regTCC_CE_ERR_STATUS_HI), - 16, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCC"}, - AMDGPU_GFX_TCC_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTA_CE_EDC_LO, regTA_CE_EDC_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TA"}, - AMDGPU_GFX_TA_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCI_CE_EDC_LO_REG, regTCI_CE_EDC_HI_REG), - 27, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCI"}, - AMDGPU_GFX_TCI_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCP_CE_EDC_LO_REG, regTCP_CE_EDC_HI_REG), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCP"}, - AMDGPU_GFX_TCP_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTD_CE_EDC_LO, regTD_CE_EDC_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TD"}, - AMDGPU_GFX_TD_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regGCEA_CE_ERR_STATUS_LO, regGCEA_CE_ERR_STATUS_HI), - 16, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "GCEA"}, - AMDGPU_GFX_GCEA_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regLDS_CE_ERR_STATUS_LO, regLDS_CE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "LDS"}, - AMDGPU_GFX_LDS_MEM, 4}, -}; - -static const struct amdgpu_gfx_ras_reg_entry gfx_v9_4_3_ue_reg_list[] = { - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regRLC_UE_ERR_STATUS_LOW, regRLC_UE_ERR_STATUS_HIGH), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "RLC"}, - AMDGPU_GFX_RLC_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regCPC_UE_ERR_STATUS_LO, regCPC_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CPC"}, - AMDGPU_GFX_CP_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regCPF_UE_ERR_STATUS_LO, regCPF_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CPF"}, - AMDGPU_GFX_CP_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regCPG_UE_ERR_STATUS_LO, regCPG_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CPG"}, - AMDGPU_GFX_CP_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regGDS_UE_ERR_STATUS_LO, regGDS_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "GDS"}, - AMDGPU_GFX_GDS_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regGC_CANE_UE_ERR_STATUS_LO, regGC_CANE_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "CANE"}, - AMDGPU_GFX_GC_CANE_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSPI_UE_ERR_STATUS_LO, regSPI_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SPI"}, - AMDGPU_GFX_SPI_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSP0_UE_ERR_STATUS_LO, regSP0_UE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SP0"}, - AMDGPU_GFX_SP_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSP1_UE_ERR_STATUS_LO, regSP1_UE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SP1"}, - AMDGPU_GFX_SP_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSQ_UE_ERR_STATUS_LO, regSQ_UE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SQ"}, - AMDGPU_GFX_SQ_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regSQC_UE_EDC_LO, regSQC_UE_EDC_HI), - 5, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SQC"}, - AMDGPU_GFX_SQC_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCX_UE_ERR_STATUS_LO, regTCX_UE_ERR_STATUS_HI), - 2, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCX"}, - AMDGPU_GFX_TCX_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCC_UE_ERR_STATUS_LO, regTCC_UE_ERR_STATUS_HI), - 16, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCC"}, - AMDGPU_GFX_TCC_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTA_UE_EDC_LO, regTA_UE_EDC_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TA"}, - AMDGPU_GFX_TA_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCI_UE_EDC_LO_REG, regTCI_UE_EDC_HI_REG), - 27, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCI"}, - AMDGPU_GFX_TCI_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCP_UE_EDC_LO_REG, regTCP_UE_EDC_HI_REG), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCP"}, - AMDGPU_GFX_TCP_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTD_UE_EDC_LO, regTD_UE_EDC_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TD"}, - AMDGPU_GFX_TD_MEM, 4}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regTCA_UE_ERR_STATUS_LO, regTCA_UE_ERR_STATUS_HI), - 2, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "TCA"}, - AMDGPU_GFX_TCA_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regGCEA_UE_ERR_STATUS_LO, regGCEA_UE_ERR_STATUS_HI), - 16, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "GCEA"}, - AMDGPU_GFX_GCEA_MEM, 1}, - {{AMDGPU_RAS_REG_ENTRY(GC, 0, regLDS_UE_ERR_STATUS_LO, regLDS_UE_ERR_STATUS_HI), - 10, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "LDS"}, - AMDGPU_GFX_LDS_MEM, 4}, -}; - -static void gfx_v9_4_3_inst_query_ras_err_count(struct amdgpu_device *adev, - void *ras_error_status, int xcc_id) -{ - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - unsigned long ce_count = 0, ue_count = 0; - uint32_t i, j, k; - - /* NOTE: convert xcc_id to physical XCD ID (XCD0 or XCD1) */ - struct amdgpu_smuio_mcm_config_info mcm_info = { - .socket_id = adev->smuio.funcs->get_socket_id(adev), - .die_id = xcc_id & 0x01 ? 1 : 0, - }; - - mutex_lock(&adev->grbm_idx_mutex); - - for (i = 0; i < ARRAY_SIZE(gfx_v9_4_3_ce_reg_list); i++) { - for (j = 0; j < gfx_v9_4_3_ce_reg_list[i].se_num; j++) { - for (k = 0; k < gfx_v9_4_3_ce_reg_list[i].reg_entry.reg_inst; k++) { - /* no need to select if instance number is 1 */ - if (gfx_v9_4_3_ce_reg_list[i].se_num > 1 || - gfx_v9_4_3_ce_reg_list[i].reg_entry.reg_inst > 1) - gfx_v9_4_3_xcc_select_se_sh(adev, j, 0, k, xcc_id); - - amdgpu_ras_inst_query_ras_error_count(adev, - &(gfx_v9_4_3_ce_reg_list[i].reg_entry), - 1, - gfx_v9_4_3_ras_mem_list_array[gfx_v9_4_3_ce_reg_list[i].mem_id_type].mem_id_ent, - gfx_v9_4_3_ras_mem_list_array[gfx_v9_4_3_ce_reg_list[i].mem_id_type].size, - GET_INST(GC, xcc_id), - AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, - &ce_count); - - amdgpu_ras_inst_query_ras_error_count(adev, - &(gfx_v9_4_3_ue_reg_list[i].reg_entry), - 1, - gfx_v9_4_3_ras_mem_list_array[gfx_v9_4_3_ue_reg_list[i].mem_id_type].mem_id_ent, - gfx_v9_4_3_ras_mem_list_array[gfx_v9_4_3_ue_reg_list[i].mem_id_type].size, - GET_INST(GC, xcc_id), - AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE, - &ue_count); - } - } - } - - /* handle extra register entries of UE */ - for (; i < ARRAY_SIZE(gfx_v9_4_3_ue_reg_list); i++) { - for (j = 0; j < gfx_v9_4_3_ue_reg_list[i].se_num; j++) { - for (k = 0; k < gfx_v9_4_3_ue_reg_list[i].reg_entry.reg_inst; k++) { - /* no need to select if instance number is 1 */ - if (gfx_v9_4_3_ue_reg_list[i].se_num > 1 || - gfx_v9_4_3_ue_reg_list[i].reg_entry.reg_inst > 1) - gfx_v9_4_3_xcc_select_se_sh(adev, j, 0, k, xcc_id); - - amdgpu_ras_inst_query_ras_error_count(adev, - &(gfx_v9_4_3_ue_reg_list[i].reg_entry), - 1, - gfx_v9_4_3_ras_mem_list_array[gfx_v9_4_3_ue_reg_list[i].mem_id_type].mem_id_ent, - gfx_v9_4_3_ras_mem_list_array[gfx_v9_4_3_ue_reg_list[i].mem_id_type].size, - GET_INST(GC, xcc_id), - AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE, - &ue_count); - } - } - } - - gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, - xcc_id); - mutex_unlock(&adev->grbm_idx_mutex); - - /* the caller should make sure initialize value of - * err_data->ue_count and err_data->ce_count - */ - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, ce_count); -} - -static void gfx_v9_4_3_inst_reset_ras_err_count(struct amdgpu_device *adev, - void *ras_error_status, int xcc_id) -{ - uint32_t i, j, k; - - mutex_lock(&adev->grbm_idx_mutex); - - for (i = 0; i < ARRAY_SIZE(gfx_v9_4_3_ce_reg_list); i++) { - for (j = 0; j < gfx_v9_4_3_ce_reg_list[i].se_num; j++) { - for (k = 0; k < gfx_v9_4_3_ce_reg_list[i].reg_entry.reg_inst; k++) { - /* no need to select if instance number is 1 */ - if (gfx_v9_4_3_ce_reg_list[i].se_num > 1 || - gfx_v9_4_3_ce_reg_list[i].reg_entry.reg_inst > 1) - gfx_v9_4_3_xcc_select_se_sh(adev, j, 0, k, xcc_id); - - amdgpu_ras_inst_reset_ras_error_count(adev, - &(gfx_v9_4_3_ce_reg_list[i].reg_entry), - 1, - GET_INST(GC, xcc_id)); - - amdgpu_ras_inst_reset_ras_error_count(adev, - &(gfx_v9_4_3_ue_reg_list[i].reg_entry), - 1, - GET_INST(GC, xcc_id)); - } - } - } - - /* handle extra register entries of UE */ - for (; i < ARRAY_SIZE(gfx_v9_4_3_ue_reg_list); i++) { - for (j = 0; j < gfx_v9_4_3_ue_reg_list[i].se_num; j++) { - for (k = 0; k < gfx_v9_4_3_ue_reg_list[i].reg_entry.reg_inst; k++) { - /* no need to select if instance number is 1 */ - if (gfx_v9_4_3_ue_reg_list[i].se_num > 1 || - gfx_v9_4_3_ue_reg_list[i].reg_entry.reg_inst > 1) - gfx_v9_4_3_xcc_select_se_sh(adev, j, 0, k, xcc_id); - - amdgpu_ras_inst_reset_ras_error_count(adev, - &(gfx_v9_4_3_ue_reg_list[i].reg_entry), - 1, - GET_INST(GC, xcc_id)); - } - } - } - - gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, - xcc_id); - mutex_unlock(&adev->grbm_idx_mutex); -} - static void gfx_v9_4_3_inst_enable_watchdog_timer(struct amdgpu_device *adev, void *ras_error_status, int xcc_id) { @@ -4610,18 +3758,6 @@ static void gfx_v9_4_3_inst_enable_watchdog_timer(struct amdgpu_device *adev, mutex_unlock(&adev->grbm_idx_mutex); } -static void gfx_v9_4_3_query_ras_error_count(struct amdgpu_device *adev, - void *ras_error_status) -{ - amdgpu_gfx_ras_error_func(adev, ras_error_status, - gfx_v9_4_3_inst_query_ras_err_count); -} - -static void gfx_v9_4_3_reset_ras_error_count(struct amdgpu_device *adev) -{ - amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_reset_ras_err_count); -} - static void gfx_v9_4_3_enable_watchdog_timer(struct amdgpu_device *adev) { amdgpu_gfx_ras_error_func(adev, NULL, gfx_v9_4_3_inst_enable_watchdog_timer); @@ -5102,37 +4238,9 @@ struct amdgpu_xcp_ip_funcs gfx_v9_4_3_xcp_funcs = { .resume = &gfx_v9_4_3_xcp_resume }; -struct amdgpu_ras_block_hw_ops gfx_v9_4_3_ras_ops = { - .query_ras_error_count = &gfx_v9_4_3_query_ras_error_count, - .reset_ras_error_count = &gfx_v9_4_3_reset_ras_error_count, -}; - -static int gfx_v9_4_3_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) -{ - int r; - - r = amdgpu_ras_block_late_init(adev, ras_block); - if (r) - return r; - - r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__GFX, - &gfx_v9_4_3_aca_info, - NULL); - if (r) - goto late_fini; - - return 0; - -late_fini: - amdgpu_ras_block_late_fini(adev, ras_block); - - return r; -} - struct amdgpu_gfx_ras gfx_v9_4_3_ras = { .ras_block = { - .hw_ops = &gfx_v9_4_3_ras_ops, - .ras_late_init = &gfx_v9_4_3_ras_late_init, + .hw_ops = NULL, }, .enable_watchdog_timer = &gfx_v9_4_3_enable_watchdog_timer, }; diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c index 8eb9847d9e1e..c40d9c467204 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v11_0.c @@ -606,6 +606,8 @@ static void gmc_v11_0_set_gfxhub_funcs(struct amdgpu_device *adev) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): adev->gfxhub.funcs = &gfxhub_v11_5_0_funcs; break; default: @@ -781,6 +783,8 @@ static int gmc_v11_0_sw_init(struct amdgpu_ip_block *ip_block) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): set_bit(AMDGPU_GFXHUB(0), adev->vmhubs_mask); set_bit(AMDGPU_MMHUB0(0), adev->vmhubs_mask); /* diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index c2a41fa3a396..64ebedc595b5 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -167,44 +167,6 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev) } } -static void gmc_v8_0_mc_stop(struct amdgpu_device *adev) -{ - u32 blackout; - struct amdgpu_ip_block *ip_block; - - ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_GMC); - if (!ip_block) - return; - - gmc_v8_0_wait_for_idle(ip_block); - - blackout = RREG32(mmMC_SHARED_BLACKOUT_CNTL); - if (REG_GET_FIELD(blackout, MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE) != 1) { - /* Block CPU access */ - WREG32(mmBIF_FB_EN, 0); - /* blackout the MC */ - blackout = REG_SET_FIELD(blackout, - MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE, 1); - WREG32(mmMC_SHARED_BLACKOUT_CNTL, blackout); - } - /* wait for the MC to settle */ - udelay(100); -} - -static void gmc_v8_0_mc_resume(struct amdgpu_device *adev) -{ - u32 tmp; - - /* unblackout the MC */ - tmp = RREG32(mmMC_SHARED_BLACKOUT_CNTL); - tmp = REG_SET_FIELD(tmp, MC_SHARED_BLACKOUT_CNTL, BLACKOUT_MODE, 0); - WREG32(mmMC_SHARED_BLACKOUT_CNTL, tmp); - /* allow CPU access */ - tmp = REG_SET_FIELD(0, BIF_FB_EN, FB_READ_EN, 1); - tmp = REG_SET_FIELD(tmp, BIF_FB_EN, FB_WRITE_EN, 1); - WREG32(mmBIF_FB_EN, tmp); -} - /** * gmc_v8_0_init_microcode - load ucode images from disk * @@ -1293,89 +1255,6 @@ static int gmc_v8_0_wait_for_idle(struct amdgpu_ip_block *ip_block) } -static bool gmc_v8_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - u32 srbm_soft_reset = 0; - struct amdgpu_device *adev = ip_block->adev; - u32 tmp = RREG32(mmSRBM_STATUS); - - if (tmp & SRBM_STATUS__VMC_BUSY_MASK) - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, - SRBM_SOFT_RESET, SOFT_RESET_VMC, 1); - - if (tmp & (SRBM_STATUS__MCB_BUSY_MASK | SRBM_STATUS__MCB_NON_DISPLAY_BUSY_MASK | - SRBM_STATUS__MCC_BUSY_MASK | SRBM_STATUS__MCD_BUSY_MASK)) { - if (!(adev->flags & AMD_IS_APU)) - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, - SRBM_SOFT_RESET, SOFT_RESET_MC, 1); - } - - if (srbm_soft_reset) { - adev->gmc.srbm_soft_reset = srbm_soft_reset; - return true; - } - - adev->gmc.srbm_soft_reset = 0; - - return false; -} - -static int gmc_v8_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - if (!adev->gmc.srbm_soft_reset) - return 0; - - gmc_v8_0_mc_stop(adev); - if (gmc_v8_0_wait_for_idle(ip_block)) - dev_warn(adev->dev, "Wait for GMC idle timed out !\n"); - - return 0; -} - -static int gmc_v8_0_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 srbm_soft_reset; - - if (!adev->gmc.srbm_soft_reset) - return 0; - srbm_soft_reset = adev->gmc.srbm_soft_reset; - - if (srbm_soft_reset) { - u32 tmp; - - tmp = RREG32(mmSRBM_SOFT_RESET); - tmp |= srbm_soft_reset; - dev_info(adev->dev, "SRBM_SOFT_RESET=0x%08X\n", tmp); - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - udelay(50); - - tmp &= ~srbm_soft_reset; - WREG32(mmSRBM_SOFT_RESET, tmp); - tmp = RREG32(mmSRBM_SOFT_RESET); - - /* Wait a little for things to settle down */ - udelay(50); - } - - return 0; -} - -static int gmc_v8_0_post_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - if (!adev->gmc.srbm_soft_reset) - return 0; - - gmc_v8_0_mc_resume(adev); - return 0; -} - static int gmc_v8_0_vm_fault_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *src, unsigned int type, @@ -1715,10 +1594,6 @@ static const struct amd_ip_funcs gmc_v8_0_ip_funcs = { .resume = gmc_v8_0_resume, .is_idle = gmc_v8_0_is_idle, .wait_for_idle = gmc_v8_0_wait_for_idle, - .check_soft_reset = gmc_v8_0_check_soft_reset, - .pre_soft_reset = gmc_v8_0_pre_soft_reset, - .soft_reset = gmc_v8_0_soft_reset, - .post_soft_reset = gmc_v8_0_post_soft_reset, .set_clockgating_state = gmc_v8_0_set_clockgating_state, .set_powergating_state = gmc_v8_0_set_powergating_state, .get_clockgating_state = gmc_v8_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c index 8a5c44810ba1..1fcc0594fd0a 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c @@ -57,6 +57,7 @@ #include "umc_v6_0.h" #include "umc_v6_7.h" #include "umc_v12_0.h" +#include "ras_umc_v12_0.h" #include "hdp_v4_0.h" #include "mca_v3_0.h" @@ -1382,7 +1383,7 @@ static void gmc_v9_0_set_umc_funcs(struct amdgpu_device *adev) case IP_VERSION(12, 0, 0): case IP_VERSION(12, 5, 0): adev->umc.max_ras_err_cnt_per_query = - UMC_V12_0_TOTAL_CHANNEL_NUM(adev) * UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL; + UMC_V12_0_TOTAL_CHANNEL_NUM * UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL; adev->umc.channel_inst_num = UMC_V12_0_CHANNEL_INSTANCE_NUM; adev->umc.umc_inst_num = UMC_V12_0_UMC_INSTANCE_NUM; adev->umc.node_inst_num /= UMC_V12_0_UMC_INSTANCE_NUM; @@ -2025,11 +2026,19 @@ static int gmc_v9_0_sw_init(struct amdgpu_ip_block *ip_block) * The first KFD VMID is 8 for GPUs with graphics, 3 for * compute-only GPUs. On compute-only GPUs that leaves 2 VMIDs * for video processing. + * + * If kernel queues are disabled, allow KFD to use all vmids. */ - adev->vm_manager.first_kfd_vmid = - (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 1) || - amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2) || - amdgpu_is_multi_aid(adev)) ? + if (adev->gfx.disable_kq && + adev->jpeg.disable_kq && + adev->vcn.disable_kq && + adev->sdma.no_user_submission) + adev->vm_manager.first_kfd_vmid = 1; + else + adev->vm_manager.first_kfd_vmid = + (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 1) || + amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(9, 4, 2) || + amdgpu_is_multi_aid(adev)) ? 3 : 8; diff --git a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c index f5927c3553ce..05b164f38c97 100644 --- a/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/imu_v11_0.c @@ -43,6 +43,8 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_2_imu.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_3_imu.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_4_imu.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_6_imu.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_0_imu.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_1_imu.bin"); static int imu_v11_0_init_microcode(struct amdgpu_device *adev) { diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c index 0c746580de11..0fdc32b3ae91 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c @@ -119,6 +119,19 @@ static int jpeg_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; + switch (amdgpu_user_queue) { + case -1: + case 0: + default: + adev->jpeg.disable_kq = false; + adev->jpeg.disable_uq = true; + break; + case 2: + adev->jpeg.disable_kq = true; + adev->jpeg.disable_uq = true; + break; + } + adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS_4_0_3; jpeg_v4_0_3_set_dec_ring_funcs(adev); @@ -175,6 +188,10 @@ static int jpeg_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block) for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { ring = &adev->jpeg.inst[i].ring_dec[j]; ring->use_doorbell = true; + if (adev->jpeg.disable_kq) { + ring->no_scheduler = true; + ring->no_user_submission = true; + } ring->vm_hub = AMDGPU_MMHUB0(adev->jpeg.inst[i].aid_id); if (!amdgpu_sriov_vf(adev)) { ring->doorbell_index = @@ -1010,7 +1027,7 @@ void jpeg_v4_0_3_dec_ring_nop(struct amdgpu_ring *ring, uint32_t count) static bool jpeg_v4_0_3_is_idle(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; - bool ret = false; + bool ret = true; int i, j; for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { @@ -1425,72 +1442,6 @@ static const struct amdgpu_ras_block_hw_ops jpeg_v4_0_3_ras_hw_ops = { .query_poison_status = jpeg_v4_0_3_query_ras_poison_status, }; -static int jpeg_v4_0_3_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct aca_bank_info info; - u64 misc0; - int ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - misc0 = bank->regs[ACA_REG_IDX_MISC0]; - switch (type) { - case ACA_SMU_TYPE_UE: - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, - 1ULL); - break; - case ACA_SMU_TYPE_CE: - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, - ACA_REG__MISC0__ERRCNT(misc0)); - break; - default: - return -EINVAL; - } - - return ret; -} - -/* reference to smu driver if header file */ -static int jpeg_v4_0_3_err_codes[] = { - 16, 17, 18, 19, 20, 21, 22, 23, /* JPEG[0-7][S|D] */ - 24, 25, 26, 27, 28, 29, 30, 31 -}; - -static bool jpeg_v4_0_3_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - u32 instlo; - - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - - if (instlo != mmSMNAID_AID0_MCA_SMU) - return false; - - if (aca_bank_check_error_codes(handle->adev, bank, - jpeg_v4_0_3_err_codes, - ARRAY_SIZE(jpeg_v4_0_3_err_codes))) - return false; - - return true; -} - -static const struct aca_bank_ops jpeg_v4_0_3_aca_bank_ops = { - .aca_bank_parser = jpeg_v4_0_3_aca_bank_parser, - .aca_bank_is_valid = jpeg_v4_0_3_aca_bank_is_valid, -}; - -static const struct aca_info jpeg_v4_0_3_aca_info = { - .hwip = ACA_HWIP_TYPE_SMU, - .mask = ACA_ERROR_UE_MASK, - .bank_ops = &jpeg_v4_0_3_aca_bank_ops, -}; - static int jpeg_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) { int r; @@ -1506,11 +1457,6 @@ static int jpeg_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_comm goto late_fini; } - r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG, - &jpeg_v4_0_3_aca_info, NULL); - if (r) - goto late_fini; - return 0; late_fini: diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c index 250316704dfa..8846cb3ed12b 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_1.c @@ -118,6 +118,19 @@ static int jpeg_v5_0_1_early_init(struct amdgpu_ip_block *ip_block) if (!adev->jpeg.num_jpeg_inst || adev->jpeg.num_jpeg_inst > AMDGPU_MAX_JPEG_INSTANCES) return -ENOENT; + switch (amdgpu_user_queue) { + case -1: + case 0: + default: + adev->jpeg.disable_kq = false; + adev->jpeg.disable_uq = true; + break; + case 2: + adev->jpeg.disable_kq = true; + adev->jpeg.disable_uq = true; + break; + } + adev->jpeg.num_jpeg_rings = AMDGPU_MAX_JPEG_RINGS; jpeg_v5_0_1_set_dec_ring_funcs(adev); jpeg_v5_0_1_set_irq_funcs(adev); @@ -172,6 +185,10 @@ static int jpeg_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block) for (j = 0; j < adev->jpeg.num_jpeg_rings; ++j) { ring = &adev->jpeg.inst[i].ring_dec[j]; ring->use_doorbell = true; + if (adev->jpeg.disable_kq) { + ring->no_scheduler = true; + ring->no_user_submission = true; + } ring->vm_hub = AMDGPU_MMHUB0(adev->jpeg.inst[i].aid_id); if (!amdgpu_sriov_vf(adev)) { ring->doorbell_index = @@ -657,7 +674,7 @@ static void jpeg_v5_0_1_dec_ring_set_wptr(struct amdgpu_ring *ring) static bool jpeg_v5_0_1_is_idle(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; - bool ret = false; + bool ret = true; int i, j; for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) { @@ -871,10 +888,7 @@ static const struct amd_ip_funcs jpeg_v5_0_1_ip_funcs = { .resume = jpeg_v5_0_1_resume, .is_idle = jpeg_v5_0_1_is_idle, .wait_for_idle = jpeg_v5_0_1_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v5_0_1_set_clockgating_state, .set_powergating_state = jpeg_v5_0_1_set_powergating_state, .dump_ip_state = amdgpu_jpeg_dump_ip_state, @@ -1003,73 +1017,6 @@ static const struct amdgpu_ras_block_hw_ops jpeg_v5_0_1_ras_hw_ops = { .query_poison_status = jpeg_v5_0_1_query_ras_poison_status, }; -static int jpeg_v5_0_1_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct aca_bank_info info; - u64 misc0; - int ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - misc0 = bank->regs[ACA_REG_IDX_MISC0]; - switch (type) { - case ACA_SMU_TYPE_UE: - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, - 1ULL); - break; - case ACA_SMU_TYPE_CE: - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, - ACA_REG__MISC0__ERRCNT(misc0)); - break; - default: - return -EINVAL; - } - - return ret; -} - -/* reference to smu driver if header file */ -static int jpeg_v5_0_1_err_codes[] = { - 16, 17, 18, 19, 20, 21, 22, 23, /* JPEG[0-9][S|D] */ - 24, 25, 26, 27, 28, 29, 30, 31, - 48, 49, 50, 51, -}; - -static bool jpeg_v5_0_1_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - u32 instlo; - - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - - if (instlo != mmSMNAID_AID0_MCA_SMU) - return false; - - if (aca_bank_check_error_codes(handle->adev, bank, - jpeg_v5_0_1_err_codes, - ARRAY_SIZE(jpeg_v5_0_1_err_codes))) - return false; - - return true; -} - -static const struct aca_bank_ops jpeg_v5_0_1_aca_bank_ops = { - .aca_bank_parser = jpeg_v5_0_1_aca_bank_parser, - .aca_bank_is_valid = jpeg_v5_0_1_aca_bank_is_valid, -}; - -static const struct aca_info jpeg_v5_0_1_aca_info = { - .hwip = ACA_HWIP_TYPE_SMU, - .mask = ACA_ERROR_UE_MASK, - .bank_ops = &jpeg_v5_0_1_aca_bank_ops, -}; - static int jpeg_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) { int r; @@ -1078,11 +1025,6 @@ static int jpeg_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_comm if (r) return r; - r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__JPEG, - &jpeg_v5_0_1_aca_info, NULL); - if (r) - goto late_fini; - if (amdgpu_ras_is_supported(adev, ras_block->block) && adev->jpeg.inst->ras_poison_irq.funcs) { r = amdgpu_irq_get(adev, &adev->jpeg.inst->ras_poison_irq, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c index 7a4ecea6b39a..ff02f72352a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c +++ b/drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_2.c @@ -690,10 +690,7 @@ static const struct amd_ip_funcs jpeg_v5_0_2_ip_funcs = { .resume = jpeg_v5_0_2_resume, .is_idle = jpeg_v5_0_2_is_idle, .wait_for_idle = jpeg_v5_0_2_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = jpeg_v5_0_2_set_clockgating_state, .set_powergating_state = jpeg_v5_0_2_set_powergating_state, .dump_ip_state = amdgpu_jpeg_dump_ip_state, diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index 16625c31bfd3..e947c16e694d 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c @@ -133,8 +133,8 @@ static int mes_userq_map(struct amdgpu_usermode_queue *queue) queue_input.gang_quantum = 10000; queue_input.paging = false; - queue_input.process_context_addr = ctx->gpu_addr; - queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ; + queue_input.process_context_addr = uq_mgr->proc_ctx_obj.gpu_addr; + queue_input.gang_context_addr = ctx->gpu_addr; queue_input.inprocess_gang_priority = AMDGPU_MES_PRIORITY_LEVEL_NORMAL; queue_input.gang_global_priority_level = convert_to_mes_priority(queue->priority); @@ -169,7 +169,8 @@ static int mes_userq_unmap(struct amdgpu_usermode_queue *queue) memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input)); queue_input.doorbell_offset = queue->doorbell_index; - queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ; + queue_input.gang_context_addr = ctx->gpu_addr; + queue_input.queue_type = queue->queue_type; amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->remove_hw_queue(&adev->mes, &queue_input); @@ -179,6 +180,63 @@ static int mes_userq_unmap(struct amdgpu_usermode_queue *queue) return r; } +int mes_userq_reset(struct amdgpu_usermode_queue *queue) +{ + struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr; + struct amdgpu_device *adev = uq_mgr->adev; + struct mes_reset_queue_input queue_input; + int r; + + /* XXX: add a FW version check for SDMA per queue reset */ + memset(&queue_input, 0x0, sizeof(struct mes_reset_queue_input)); + queue_input.doorbell_offset = queue->doorbell_index; + queue_input.queue_type = queue->queue_type; + + amdgpu_mes_lock(&adev->mes); + r = adev->mes.funcs->reset_hw_queue(&adev->mes, &queue_input); + amdgpu_mes_unlock(&adev->mes); + if (r) + return r; + return mes_userq_unmap(queue); +} + +int mes_userq_reset_queue(struct amdgpu_device *adev, + struct amdgpu_usermode_queue *guilty_uq, + int queue_type, + unsigned int pipe, + unsigned int queue, + unsigned int db) +{ + struct amdgpu_usermode_queue *uq; + bool use_mmio = adev->gfx.mec.use_mmio_for_reset; + unsigned long uq_id; + int r; + + xa_for_each(&adev->userq_doorbell_xa, uq_id, uq) { + if (uq->queue_type == queue_type) { + if (uq == guilty_uq) + continue; + if (uq->doorbell_index == db) { + uq->state = AMDGPU_USERQ_STATE_HUNG; + if (use_mmio) + r = amdgpu_mes_reset_queue_mmio(adev, queue_type, 0, 1, pipe, queue, 0); + else + r = amdgpu_mes_reset_user_queue(adev, queue_type, db, 0); + if (r) + return r; + r = mes_userq_unmap(uq); + if (r) + return r; + atomic_inc(&adev->gpu_reset_counter); + amdgpu_userq_fence_driver_force_completion(uq); + drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, NULL); + break; + } + } + } + return 0; +} + static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue, struct drm_amdgpu_userq_in *mqd_user) @@ -186,12 +244,8 @@ static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_userq_obj *ctx = &queue->fw_obj; int r, size; - /* - * The FW expects at least one page space allocated for - * process ctx and gang ctx each. Create an object - * for the same. - */ - size = AMDGPU_USERQ_PROC_CTX_SZ + AMDGPU_USERQ_GANG_CTX_SZ; + /* The FW expects at least one page space allocated for gang ctx. */ + size = AMDGPU_USERQ_GANG_CTX_SZ; r = amdgpu_bo_create_kernel(uq_mgr->adev, size, 0, AMDGPU_GEM_DOMAIN_GTT, &ctx->obj, &ctx->gpu_addr, @@ -205,54 +259,26 @@ static int mes_userq_create_ctx_space(struct amdgpu_userq_mgr *uq_mgr, return 0; } -static int mes_userq_detect_and_reset(struct amdgpu_device *adev, - int queue_type) +static int mes_userq_create_proc_ctx_space(struct amdgpu_userq_mgr *uq_mgr) { - int db_array_size = amdgpu_mes_get_hung_queue_db_array_size(adev); - struct mes_detect_and_reset_queue_input input; - struct amdgpu_usermode_queue *queue; - unsigned int hung_db_num = 0; - unsigned long queue_id; - u32 db_array[8]; - bool found_hung_queue = false; - int r, i; + int r = 0; - if (db_array_size > 8) { - dev_err(adev->dev, "DB array size (%d vs 8) too small\n", - db_array_size); - return -EINVAL; + mutex_lock(&uq_mgr->proc_ctx_lock); + /* This check is a necessary because amdgpu_bo_create_kernel() + * calls helpers like amdgpu_bo_pin() and memset() unconditionally + */ + if (!uq_mgr->proc_ctx_obj.obj) { + r = amdgpu_bo_create_kernel(uq_mgr->adev, AMDGPU_USERQ_PROC_CTX_SZ, + 0, AMDGPU_GEM_DOMAIN_GTT, + &uq_mgr->proc_ctx_obj.obj, + &uq_mgr->proc_ctx_obj.gpu_addr, + &uq_mgr->proc_ctx_obj.cpu_ptr); + + if (!r) + memset(uq_mgr->proc_ctx_obj.cpu_ptr, 0, AMDGPU_USERQ_PROC_CTX_SZ); } - memset(&input, 0x0, sizeof(struct mes_detect_and_reset_queue_input)); - - input.queue_type = queue_type; - - amdgpu_mes_lock(&adev->mes); - r = amdgpu_mes_detect_and_reset_hung_queues(adev, queue_type, false, - &hung_db_num, db_array, 0); - amdgpu_mes_unlock(&adev->mes); - if (r) { - dev_err(adev->dev, "Failed to detect and reset queues, err (%d)\n", r); - } else if (hung_db_num) { - xa_for_each(&adev->userq_doorbell_xa, queue_id, queue) { - if (queue->queue_type == queue_type) { - for (i = 0; i < hung_db_num; i++) { - if (queue->doorbell_index == db_array[i]) { - queue->state = AMDGPU_USERQ_STATE_HUNG; - found_hung_queue = true; - atomic_inc(&adev->gpu_reset_counter); - amdgpu_userq_fence_driver_force_completion(queue); - drm_dev_wedged_event(adev_to_drm(adev), DRM_WEDGE_RECOVERY_NONE, NULL); - } - } - } - } - } - - if (found_hung_queue) { - /* Resume scheduling after hang recovery */ - r = amdgpu_mes_resume(adev, input.xcc_id); - } + mutex_unlock(&uq_mgr->proc_ctx_lock); return r; } @@ -429,7 +455,14 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue, goto free_mqd; } - /* Create BO for FW operations */ + /* Create per-process MES process context BO */ + r = mes_userq_create_proc_ctx_space(uq_mgr); + if (r) { + DRM_ERROR("Failed to allocate MES process context space bo, error: %d\n", r); + goto free_mqd; + } + + /* Create BO of a gang for FW operations */ r = mes_userq_create_ctx_space(uq_mgr, queue, mqd_user); if (r) { DRM_ERROR("Failed to allocate BO for userqueue (%d)", r); @@ -497,7 +530,7 @@ static int mes_userq_preempt(struct amdgpu_usermode_queue *queue) *fence_ptr = 0; memset(&queue_input, 0x0, sizeof(struct mes_suspend_gang_input)); - queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ; + queue_input.gang_context_addr = ctx->gpu_addr; queue_input.suspend_fence_addr = fence_gpu_addr; queue_input.suspend_fence_value = 1; amdgpu_mes_lock(&adev->mes); @@ -534,7 +567,7 @@ static int mes_userq_restore(struct amdgpu_usermode_queue *queue) return 0; memset(&queue_input, 0x0, sizeof(struct mes_resume_gang_input)); - queue_input.gang_context_addr = ctx->gpu_addr + AMDGPU_USERQ_PROC_CTX_SZ; + queue_input.gang_context_addr = ctx->gpu_addr; amdgpu_mes_lock(&adev->mes); r = adev->mes.funcs->resume_gang(&adev->mes, &queue_input); @@ -549,7 +582,7 @@ const struct amdgpu_userq_funcs userq_mes_funcs = { .mqd_destroy = mes_userq_mqd_destroy, .unmap = mes_userq_unmap, .map = mes_userq_map, - .detect_and_reset = mes_userq_detect_and_reset, .preempt = mes_userq_preempt, .restore = mes_userq_restore, + .reset = mes_userq_reset, }; diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.h b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.h index 090ae8897770..a473360d6a8b 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.h +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.h @@ -27,4 +27,13 @@ #include "amdgpu_userq.h" extern const struct amdgpu_userq_funcs userq_mes_funcs; + +int mes_userq_reset(struct amdgpu_usermode_queue *queue); +int mes_userq_reset_queue(struct amdgpu_device *adev, + struct amdgpu_usermode_queue *guilty_uq, + int queue_type, + unsigned int pipe, + unsigned int queue, + unsigned int db); + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c index ac6d4f277336..8f136ff7d96f 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v11_0.c @@ -60,6 +60,10 @@ MODULE_FIRMWARE("amdgpu/gc_11_5_4_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_4_mes1.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_6_mes_2.bin"); MODULE_FIRMWARE("amdgpu/gc_11_5_6_mes1.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_0_mes_2.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_0_mes1.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_1_mes_2.bin"); +MODULE_FIRMWARE("amdgpu/gc_11_7_1_mes1.bin"); static int mes_v11_0_hw_init(struct amdgpu_ip_block *ip_block); static int mes_v11_0_hw_fini(struct amdgpu_ip_block *ip_block); @@ -383,6 +387,8 @@ static int mes_v11_0_remove_hw_queue(struct amdgpu_mes *mes, mes_remove_queue_pkt.doorbell_offset = input->doorbell_offset; mes_remove_queue_pkt.gang_context_addr = input->gang_context_addr; + mes_remove_queue_pkt.queue_type = + convert_to_mes_queue_type(input->queue_type); if (mes_rev >= 0x60) mes_remove_queue_pkt.remove_queue_after_reset = input->remove_queue_after_reset; @@ -392,6 +398,230 @@ static int mes_v11_0_remove_hw_queue(struct amdgpu_mes *mes, offsetof(union MESAPI__REMOVE_QUEUE, api_status)); } +static bool mes_v11_0_pipe_reset_support(struct amdgpu_device *adev) +{ + /* Disable the pipe reset until the CPFW fully support it.*/ + dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n"); + return false; +} +static int mes_v11_0_reset_gfx_pipe_mmio(struct amdgpu_device *adev, + u32 me, u32 pipe, u32 queue) +{ + uint32_t reset_pipe = 0, clean_pipe = 0; + int r; + + if (!mes_v11_0_pipe_reset_support(adev)) + return -EOPNOTSUPP; + + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + mutex_lock(&adev->srbm_mutex); + soc21_grbm_select(adev, me, pipe, queue, 0); + + switch (pipe) { + case 0: + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + PFP_PIPE0_RESET, 1); + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + ME_PIPE0_RESET, 1); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + PFP_PIPE0_RESET, 0); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + ME_PIPE0_RESET, 0); + break; + case 1: + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + PFP_PIPE1_RESET, 1); + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + ME_PIPE1_RESET, 1); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + PFP_PIPE1_RESET, 0); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + ME_PIPE1_RESET, 0); + break; + default: + break; + } + + WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe); + WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe); + + r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) - + RS64_FW_UC_START_ADDR_LO; + soc21_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + + dev_info(adev->dev, "The gfx pipe reset to the ME firmware start PC: %s\n", + r == 0 ? "successfully" : "failed"); + /* FIXME: Sometimes driver can't cache the ME firmware start PC correctly, + * so the pipe reset status relies on the later gfx ring test result. + */ + return 0; +} + +/* + * With MEC pipe reset asserted, clear CP_HQD_ACTIVE / CP_HQD_DEQUEUE_REQUEST for + * every queue on (me, pipe). HQDs must be torn down while pipe reset stays + * asserted; only then clear the pipe reset bit. + * Caller must hold adev->srbm_mutex. + */ +static void mes_v11_0_clear_hqds_on_mec_pipe(struct amdgpu_device *adev, u32 me, + u32 pipe) +{ + unsigned int q; + + for (q = 0; q < adev->gfx.mec.num_queue_per_pipe; q++) { + soc21_grbm_select(adev, me, pipe, q, 0); + /* Start from a clean HQD dequeue state before forcing HQD inactive. */ + WREG32_SOC15(GC, 0, regCP_HQD_ACTIVE, 0); + WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0); + } +} + +static int mes_v11_0_reset_compute_pipe_mmio(struct amdgpu_device *adev, + u32 me, u32 pipe, u32 queue) +{ + uint32_t reset_val, clean_val; + int r; + + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + mutex_lock(&adev->srbm_mutex); + soc21_grbm_select(adev, me, pipe, queue, 0); + + if (adev->gfx.rs64_enable) { + reset_val = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL); + clean_val = reset_val; + + switch (pipe) { + case 0: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE0_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE0_RESET, 0); + break; + case 1: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE1_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE1_RESET, 0); + break; + case 2: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE2_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE2_RESET, 0); + break; + case 3: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE3_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE3_RESET, 0); + break; + default: + break; + } + WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_val); + mes_v11_0_clear_hqds_on_mec_pipe(adev, me, pipe); + WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_val); + r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) - + RS64_FW_UC_START_ADDR_LO; + } else { + reset_val = RREG32_SOC15(GC, 0, regCP_MEC_CNTL); + clean_val = reset_val; + + if (me == 1) { + switch (pipe) { + case 0: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME1_PIPE0_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME1_PIPE0_RESET, 0); + break; + case 1: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME1_PIPE1_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME1_PIPE1_RESET, 0); + break; + case 2: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME1_PIPE2_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME1_PIPE2_RESET, 0); + break; + case 3: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME1_PIPE3_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME1_PIPE3_RESET, 0); + break; + default: + break; + } + /* mec1 fw pc: CP_MEC1_INSTR_PNTR */ + } else { + switch (pipe) { + case 0: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME2_PIPE0_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME2_PIPE0_RESET, 0); + break; + case 1: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME2_PIPE1_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME2_PIPE1_RESET, 0); + break; + case 2: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME2_PIPE2_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME2_PIPE2_RESET, 0); + break; + case 3: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME2_PIPE3_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME2_PIPE3_RESET, 0); + break; + default: + break; + } + /* mec2 fw pc: CP:CP_MEC2_INSTR_PNTR */ + } + WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_val); + mes_v11_0_clear_hqds_on_mec_pipe(adev, me, pipe); + WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_val); + r = RREG32(SOC15_REG_OFFSET(GC, 0, regCP_MEC1_INSTR_PNTR)); + } + + soc21_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + + dev_dbg(adev->dev, "MEC pipe me%u pipe%u queue%u resets to MEC FW start PC: %s\n", + me, pipe, queue, r == 0 ? "successfully" : "failed"); + /*FIXME:Sometimes driver can't cache the MEC firmware start PC correctly, so the pipe + * reset status relies on the compute ring test result. + */ + return 0; +} + +static int mes_v11_0_reset_pipe_mmio(struct amdgpu_mes *mes, uint32_t queue_type, + uint32_t me_id, uint32_t pipe_id, + uint32_t queue_id, uint32_t vmid) +{ + struct amdgpu_device *adev = mes->adev; + + if (queue_type == AMDGPU_RING_TYPE_GFX) + return mes_v11_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, queue_id); + else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) + return mes_v11_0_reset_compute_pipe_mmio(adev, me_id, pipe_id, queue_id); + else + return -EOPNOTSUPP; +} + static int mes_v11_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_type, uint32_t me_id, uint32_t pipe_id, uint32_t queue_id, uint32_t vmid) @@ -559,6 +789,7 @@ static int mes_v11_0_suspend_gang(struct amdgpu_mes *mes, mes_suspend_gang_pkt.gang_context_addr = input->gang_context_addr; mes_suspend_gang_pkt.suspend_fence_addr = input->suspend_fence_addr; mes_suspend_gang_pkt.suspend_fence_value = input->suspend_fence_value; + mes_suspend_gang_pkt.doorbell_offset = input->doorbell_offset; return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_suspend_gang_pkt, sizeof(mes_suspend_gang_pkt), @@ -578,6 +809,7 @@ static int mes_v11_0_resume_gang(struct amdgpu_mes *mes, mes_resume_gang_pkt.resume_all_gangs = input->resume_all_gangs; mes_resume_gang_pkt.gang_context_addr = input->gang_context_addr; + mes_resume_gang_pkt.doorbell_offset = input->doorbell_offset; return mes_v11_0_submit_pkt_and_poll_completion(mes, &mes_resume_gang_pkt, sizeof(mes_resume_gang_pkt), @@ -764,10 +996,16 @@ static int mes_v11_0_reset_hw_queue(struct amdgpu_mes *mes, { union MESAPI__RESET mes_reset_queue_pkt; - if (input->use_mmio) - return mes_v11_0_reset_queue_mmio(mes, input->queue_type, - input->me_id, input->pipe_id, - input->queue_id, input->vmid); + if (input->use_mmio) { + int r = mes_v11_0_reset_queue_mmio(mes, input->queue_type, + input->me_id, input->pipe_id, + input->queue_id, input->vmid); + if (r) + return mes_v11_0_reset_pipe_mmio(mes, input->queue_type, + input->me_id, input->pipe_id, + input->queue_id, input->vmid); + return 0; + } memset(&mes_reset_queue_pkt, 0, sizeof(mes_reset_queue_pkt)); diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c index 7453fb11289e..ce5064200743 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_0.c @@ -26,7 +26,7 @@ #include "amdgpu.h" #include "gfx_v12_0.h" #include "soc15_common.h" -#include "soc21.h" +#include "soc24.h" #include "gc/gc_12_0_0_offset.h" #include "gc/gc_12_0_0_sh_mask.h" #include "gc/gc_11_0_0_default.h" @@ -371,6 +371,8 @@ static int mes_v12_0_remove_hw_queue(struct amdgpu_mes *mes, mes_remove_queue_pkt.doorbell_offset = input->doorbell_offset; mes_remove_queue_pkt.gang_context_addr = input->gang_context_addr; + mes_remove_queue_pkt.queue_type = + convert_to_mes_queue_type(input->queue_type); if (mes_rev >= 0x5a) mes_remove_queue_pkt.remove_queue_after_reset = input->remove_queue_after_reset; @@ -413,6 +415,171 @@ int gfx_v12_0_request_gfx_index_mutex(struct amdgpu_device *adev, return 0; } +static bool mes_v12_0_pipe_reset_support(struct amdgpu_device *adev) +{ + /* Disable the pipe reset until the CPFW fully support it.*/ + dev_warn_once(adev->dev, "The CPFW hasn't support pipe reset yet.\n"); + return false; +} + +static int mes_v12_0_reset_gfx_pipe_mmio(struct amdgpu_device *adev, + u32 me, u32 pipe, u32 queue) +{ + uint32_t reset_pipe = 0, clean_pipe = 0; + int r; + + if (!mes_v12_0_pipe_reset_support(adev)) + return -EOPNOTSUPP; + + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + mutex_lock(&adev->srbm_mutex); + soc24_grbm_select(adev, me, pipe, queue, 0); + + switch (pipe) { + case 0: + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + PFP_PIPE0_RESET, 1); + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + ME_PIPE0_RESET, 1); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + PFP_PIPE0_RESET, 0); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + ME_PIPE0_RESET, 0); + break; + case 1: + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + PFP_PIPE1_RESET, 1); + reset_pipe = REG_SET_FIELD(reset_pipe, CP_ME_CNTL, + ME_PIPE1_RESET, 1); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + PFP_PIPE1_RESET, 0); + clean_pipe = REG_SET_FIELD(clean_pipe, CP_ME_CNTL, + ME_PIPE1_RESET, 0); + break; + default: + break; + } + + WREG32_SOC15(GC, 0, regCP_ME_CNTL, reset_pipe); + WREG32_SOC15(GC, 0, regCP_ME_CNTL, clean_pipe); + + r = (RREG32(SOC15_REG_OFFSET(GC, 0, regCP_GFX_RS64_INSTR_PNTR1)) << 2) - + RS64_FW_UC_START_ADDR_LO; + soc24_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + + dev_info(adev->dev, "The gfx pipe reset: %s\n", + r == 0 ? "successfully" : "failed"); + /* Sometimes the ME start pc counter can't cache correctly, so the + * PC check only as a reference and pipe reset result rely on the + * later ring test. + */ + return 0; +} + +/* + * With MEC pipe reset asserted, clear CP_HQD_ACTIVE / CP_HQD_DEQUEUE_REQUEST for + * every queue on (me, pipe). HQDs must be torn down while pipe reset stays + * asserted; only then clear the pipe reset bit. + * Caller must hold adev->srbm_mutex. + */ +static void mes_v12_0_clear_hqds_on_mec_pipe(struct amdgpu_device *adev, u32 me, + u32 pipe) +{ + unsigned int q; + + for (q = 0; q < adev->gfx.mec.num_queue_per_pipe; q++) { + soc24_grbm_select(adev, me, pipe, q, 0); + /* Start from a clean HQD dequeue state before forcing HQD inactive. */ + WREG32_SOC15(GC, 0, regCP_HQD_ACTIVE, 0); + WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0); + } +} + +static int mes_v12_0_reset_compute_pipe_mmio(struct amdgpu_device *adev, + u32 me, u32 pipe, u32 queue) +{ + uint32_t reset_val, clean_val; + int r = 0; + + amdgpu_gfx_rlc_enter_safe_mode(adev, 0); + mutex_lock(&adev->srbm_mutex); + soc24_grbm_select(adev, me, pipe, queue, 0); + if (adev->gfx.rs64_enable) { + reset_val = RREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL); + clean_val = reset_val; + + switch (pipe) { + case 0: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE0_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE0_RESET, 0); + break; + case 1: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE1_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE1_RESET, 0); + break; + case 2: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE2_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE2_RESET, 0); + break; + case 3: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_RS64_CNTL, + MEC_PIPE3_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_RS64_CNTL, + MEC_PIPE3_RESET, 0); + break; + default: + break; + } + WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, reset_val); + mes_v12_0_clear_hqds_on_mec_pipe(adev, me, pipe); + soc24_grbm_select(adev, me, pipe, queue, 0); + WREG32_SOC15(GC, 0, regCP_MEC_RS64_CNTL, clean_val); + r = (RREG32_SOC15(GC, 0, regCP_MEC_RS64_INSTR_PNTR) << 2) - + RS64_FW_UC_START_ADDR_LO; + } else { + reset_val = RREG32_SOC15(GC, 0, regCP_MEC_CNTL); + clean_val = reset_val; + + switch (pipe) { + case 0: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME1_PIPE0_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME1_PIPE0_RESET, 0); + break; + case 1: + reset_val = REG_SET_FIELD(reset_val, CP_MEC_CNTL, + MEC_ME1_PIPE1_RESET, 1); + clean_val = REG_SET_FIELD(clean_val, CP_MEC_CNTL, + MEC_ME1_PIPE1_RESET, 0); + break; + default: + break; + } + + WREG32_SOC15(GC, 0, regCP_MEC_CNTL, reset_val); + mes_v12_0_clear_hqds_on_mec_pipe(adev, me, pipe); + soc24_grbm_select(adev, me, pipe, queue, 0); + WREG32_SOC15(GC, 0, regCP_MEC_CNTL, clean_val); + } + + soc24_grbm_select(adev, 0, 0, 0, 0); + mutex_unlock(&adev->srbm_mutex); + amdgpu_gfx_rlc_exit_safe_mode(adev, 0); + + dev_dbg(adev->dev, "MEC pipe me%u pipe%u queue%u resets to MEC FW start PC: %s\n", + me, pipe, queue, r == 0 ? "successfully" : "failed"); + return 0; +} + static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_type, uint32_t me_id, uint32_t pipe_id, uint32_t queue_id, uint32_t vmid) @@ -442,7 +609,7 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ mutex_unlock(&adev->gfx.reset_sem_mutex); mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, me_id, pipe_id, queue_id, 0); + soc24_grbm_select(adev, me_id, pipe_id, queue_id, 0); /* wait till dequeue take effects */ for (i = 0; i < adev->usec_timeout; i++) { if (!(RREG32_SOC15(GC, 0, regCP_GFX_HQD_ACTIVE) & 1)) @@ -454,13 +621,13 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ r = -ETIMEDOUT; } - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); } else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) { dev_info(adev->dev, "reset compute queue (%d:%d:%d)\n", me_id, pipe_id, queue_id); mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, me_id, pipe_id, queue_id, 0); + soc24_grbm_select(adev, me_id, pipe_id, queue_id, 0); WREG32_SOC15(GC, 0, regCP_HQD_DEQUEUE_REQUEST, 0x2); WREG32_SOC15(GC, 0, regSPI_COMPUTE_QUEUE_RESET, 0x1); @@ -474,7 +641,7 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ dev_err(adev->dev, "failed to wait on hqd deactivate\n"); r = -ETIMEDOUT; } - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); } else if (queue_type == AMDGPU_RING_TYPE_SDMA) { dev_info(adev->dev, "reset sdma queue (%d:%d:%d)\n", @@ -507,6 +674,20 @@ static int mes_v12_0_reset_queue_mmio(struct amdgpu_mes *mes, uint32_t queue_typ return r; } +static int mes_v12_0_reset_pipe_mmio(struct amdgpu_mes *mes, uint32_t queue_type, + uint32_t me_id, uint32_t pipe_id, + uint32_t queue_id, uint32_t vmid) +{ + struct amdgpu_device *adev = mes->adev; + + if (queue_type == AMDGPU_RING_TYPE_GFX) + return mes_v12_0_reset_gfx_pipe_mmio(adev, me_id, pipe_id, queue_id); + else if (queue_type == AMDGPU_RING_TYPE_COMPUTE) + return mes_v12_0_reset_compute_pipe_mmio(adev, me_id, pipe_id, queue_id); + else + return -EOPNOTSUPP; +} + static int mes_v12_0_map_legacy_queue(struct amdgpu_mes *mes, struct mes_map_legacy_queue_input *input) { @@ -528,10 +709,15 @@ static int mes_v12_0_map_legacy_queue(struct amdgpu_mes *mes, convert_to_mes_queue_type(input->queue_type); mes_add_queue_pkt.map_legacy_kq = 1; - if (mes->adev->enable_uni_mes) - pipe = AMDGPU_MES_KIQ_PIPE; - else + if (mes->adev->enable_uni_mes) { + /* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */ + if (input->queue_type == AMDGPU_RING_TYPE_MES) + pipe = AMDGPU_MES_KIQ_PIPE; + else + pipe = AMDGPU_MES_SCHED_PIPE; + } else { pipe = AMDGPU_MES_SCHED_PIPE; + } return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe, &mes_add_queue_pkt, sizeof(mes_add_queue_pkt), @@ -565,12 +751,28 @@ static int mes_v12_0_unmap_legacy_queue(struct amdgpu_mes *mes, mes_remove_queue_pkt.unmap_legacy_queue = 1; mes_remove_queue_pkt.queue_type = convert_to_mes_queue_type(input->queue_type); + /* + * A reset-time unmap: the queue was already reset via MMIO while + * gangs are suspended and it is on the MES hung/fail list. Tell + * MES to just drop its internal state for it. Without this flag + * MES asks CP to unmap the already-reset (still wedged) queue + * again, which times out and forces a GPU reset. + */ + if (input->action == RESET_QUEUES && + (mes->sched_version & AMDGPU_MES_VERSION_MASK) >= 0x5a) + mes_remove_queue_pkt.remove_queue_after_reset = 1; + } - if (mes->adev->enable_uni_mes) - pipe = AMDGPU_MES_KIQ_PIPE; - else + if (mes->adev->enable_uni_mes) { + /* Keep scheduler queue on KIQ pipe; unmap all other kernel queues on sched pipe. */ + if (input->queue_type == AMDGPU_RING_TYPE_MES) + pipe = AMDGPU_MES_KIQ_PIPE; + else + pipe = AMDGPU_MES_SCHED_PIPE; + } else { pipe = AMDGPU_MES_SCHED_PIPE; + } return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe, &mes_remove_queue_pkt, sizeof(mes_remove_queue_pkt), @@ -592,6 +794,7 @@ static int mes_v12_0_suspend_gang(struct amdgpu_mes *mes, mes_suspend_gang_pkt.gang_context_addr = input->gang_context_addr; mes_suspend_gang_pkt.suspend_fence_addr = input->suspend_fence_addr; mes_suspend_gang_pkt.suspend_fence_value = input->suspend_fence_value; + mes_suspend_gang_pkt.doorbell_offset = input->doorbell_offset; return mes_v12_0_submit_pkt_and_poll_completion(mes, AMDGPU_MES_SCHED_PIPE, &mes_suspend_gang_pkt, sizeof(mes_suspend_gang_pkt), @@ -611,6 +814,7 @@ static int mes_v12_0_resume_gang(struct amdgpu_mes *mes, mes_resume_gang_pkt.resume_all_gangs = input->resume_all_gangs; mes_resume_gang_pkt.gang_context_addr = input->gang_context_addr; + mes_resume_gang_pkt.doorbell_offset = input->doorbell_offset; return mes_v12_0_submit_pkt_and_poll_completion(mes, AMDGPU_MES_SCHED_PIPE, &mes_resume_gang_pkt, sizeof(mes_resume_gang_pkt), @@ -886,10 +1090,16 @@ static int mes_v12_0_reset_hw_queue(struct amdgpu_mes *mes, union MESAPI__RESET mes_reset_queue_pkt; int pipe; - if (input->use_mmio) - return mes_v12_0_reset_queue_mmio(mes, input->queue_type, - input->me_id, input->pipe_id, - input->queue_id, input->vmid); + if (input->use_mmio) { + int r = mes_v12_0_reset_queue_mmio(mes, input->queue_type, + input->me_id, input->pipe_id, + input->queue_id, input->vmid); + if (r) + return mes_v12_0_reset_pipe_mmio(mes, input->queue_type, + input->me_id, input->pipe_id, + input->queue_id, input->vmid); + return 0; + } memset(&mes_reset_queue_pkt, 0, sizeof(mes_reset_queue_pkt)); @@ -913,10 +1123,7 @@ static int mes_v12_0_reset_hw_queue(struct amdgpu_mes *mes, mes_reset_queue_pkt.doorbell_offset = input->doorbell_offset; } - if (input->is_kq) - pipe = AMDGPU_MES_KIQ_PIPE; - else - pipe = AMDGPU_MES_SCHED_PIPE; + pipe = AMDGPU_MES_SCHED_PIPE; return mes_v12_0_submit_pkt_and_poll_completion(mes, pipe, &mes_reset_queue_pkt, sizeof(mes_reset_queue_pkt), @@ -1092,7 +1299,7 @@ static void mes_v12_0_enable(struct amdgpu_device *adev, bool enable) if (enable) { mutex_lock(&adev->srbm_mutex); for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { - soc21_grbm_select(adev, 3, pipe, 0, 0); + soc24_grbm_select(adev, 3, pipe, 0, 0); if (amdgpu_mes_log_enable) { u32 log_size = AMDGPU_MES_LOG_BUFFER_SIZE + AMDGPU_MES_MSCRATCH_SIZE; /* In case uni mes is not enabled, only program for pipe 0 */ @@ -1131,7 +1338,7 @@ static void mes_v12_0_enable(struct amdgpu_device *adev, bool enable) WREG32_SOC15(GC, 0, regCP_MES_CNTL, data); } - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); if (amdgpu_emu_mode) @@ -1163,7 +1370,7 @@ static void mes_v12_0_set_ucode_start_addr(struct amdgpu_device *adev) mutex_lock(&adev->srbm_mutex); for (pipe = 0; pipe < AMDGPU_MAX_MES_PIPES; pipe++) { /* me=3, queue=0 */ - soc21_grbm_select(adev, 3, pipe, 0, 0); + soc24_grbm_select(adev, 3, pipe, 0, 0); /* set ucode start address */ ucode_addr = adev->mes.uc_start_addr[pipe] >> 2; @@ -1172,7 +1379,7 @@ static void mes_v12_0_set_ucode_start_addr(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, regCP_MES_PRGRM_CNTR_START_HI, upper_32_bits(ucode_addr)); - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); } mutex_unlock(&adev->srbm_mutex); } @@ -1201,7 +1408,7 @@ static int mes_v12_0_load_microcode(struct amdgpu_device *adev, mutex_lock(&adev->srbm_mutex); /* me=3, pipe=0, queue=0 */ - soc21_grbm_select(adev, 3, pipe, 0, 0); + soc24_grbm_select(adev, 3, pipe, 0, 0); WREG32_SOC15(GC, 0, regCP_MES_IC_BASE_CNTL, 0); @@ -1236,7 +1443,7 @@ static int mes_v12_0_load_microcode(struct amdgpu_device *adev, WREG32_SOC15(GC, 0, regCP_MES_IC_OP_CNTL, data); } - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); return 0; @@ -1383,7 +1590,7 @@ static void mes_v12_0_queue_init_register(struct amdgpu_ring *ring) uint32_t data = 0; mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, 3, ring->pipe, 0, 0); + soc24_grbm_select(adev, 3, ring->pipe, 0, 0); /* set CP_HQD_VMID.VMID = 0. */ data = RREG32_SOC15(GC, 0, regCP_HQD_VMID); @@ -1434,7 +1641,7 @@ static void mes_v12_0_queue_init_register(struct amdgpu_ring *ring) /* set CP_HQD_ACTIVE.ACTIVE=1 */ WREG32_SOC15(GC, 0, regCP_HQD_ACTIVE, mqd->cp_hqd_active); - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); } @@ -1500,14 +1707,14 @@ static int mes_v12_0_queue_init(struct amdgpu_device *adev, ((pipe == AMDGPU_MES_KIQ_PIPE) && !adev->mes.kiq_version)) { /* get MES scheduler/KIQ versions */ mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, 3, pipe, 0, 0); + soc24_grbm_select(adev, 3, pipe, 0, 0); if (pipe == AMDGPU_MES_SCHED_PIPE) adev->mes.sched_version = RREG32_SOC15(GC, 0, regCP_MES_GP3_LO); else if (pipe == AMDGPU_MES_KIQ_PIPE && adev->enable_mes_kiq) adev->mes.kiq_version = RREG32_SOC15(GC, 0, regCP_MES_GP3_LO); - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); } @@ -1695,7 +1902,7 @@ static void mes_v12_0_kiq_dequeue_sched(struct amdgpu_device *adev) int i; mutex_lock(&adev->srbm_mutex); - soc21_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0); + soc24_grbm_select(adev, 3, AMDGPU_MES_SCHED_PIPE, 0, 0); /* disable the queue if it's active */ if (RREG32_SOC15(GC, 0, regCP_HQD_ACTIVE) & 1) { @@ -1719,7 +1926,7 @@ static void mes_v12_0_kiq_dequeue_sched(struct amdgpu_device *adev) WREG32_SOC15(GC, 0, regCP_HQD_PQ_WPTR_HI, 0); WREG32_SOC15(GC, 0, regCP_HQD_PQ_RPTR, 0); - soc21_grbm_select(adev, 0, 0, 0, 0); + soc24_grbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); adev->mes.ring[0].sched.ready = false; diff --git a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c index 8a90ad5a51b8..f7d5879c6e44 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_v12_1.c @@ -362,6 +362,8 @@ static int mes_v12_1_remove_hw_queue(struct amdgpu_mes *mes, mes_remove_queue_pkt.doorbell_offset = input->doorbell_offset; mes_remove_queue_pkt.gang_context_addr = input->gang_context_addr; + mes_remove_queue_pkt.queue_type = + convert_to_mes_queue_type(input->queue_type); return mes_v12_1_submit_pkt_and_poll_completion(mes, xcc_id, AMDGPU_MES_SCHED_PIPE, @@ -417,10 +419,15 @@ static int mes_v12_1_map_legacy_queue(struct amdgpu_mes *mes, convert_to_mes_queue_type(input->queue_type); mes_add_queue_pkt.map_legacy_kq = 1; - if (mes->adev->enable_uni_mes) - pipe = AMDGPU_MES_KIQ_PIPE; - else + if (mes->adev->enable_uni_mes) { + /* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */ + if (input->queue_type == AMDGPU_RING_TYPE_MES) + pipe = AMDGPU_MES_KIQ_PIPE; + else + pipe = AMDGPU_MES_SCHED_PIPE; + } else { pipe = AMDGPU_MES_SCHED_PIPE; + } return mes_v12_1_submit_pkt_and_poll_completion(mes, input->xcc_id, pipe, @@ -457,10 +464,15 @@ static int mes_v12_1_unmap_legacy_queue(struct amdgpu_mes *mes, convert_to_mes_queue_type(input->queue_type); } - if (mes->adev->enable_uni_mes) - pipe = AMDGPU_MES_KIQ_PIPE; - else + if (mes->adev->enable_uni_mes) { + /* Keep scheduler queue on KIQ pipe; map all other kernel queues on sched pipe. */ + if (input->queue_type == AMDGPU_RING_TYPE_MES) + pipe = AMDGPU_MES_KIQ_PIPE; + else + pipe = AMDGPU_MES_SCHED_PIPE; + } else { pipe = AMDGPU_MES_SCHED_PIPE; + } return mes_v12_1_submit_pkt_and_poll_completion(mes, input->xcc_id, pipe, @@ -484,6 +496,7 @@ static int mes_v12_1_suspend_gang(struct amdgpu_mes *mes, mes_suspend_gang_pkt.gang_context_addr = input->gang_context_addr; mes_suspend_gang_pkt.suspend_fence_addr = input->suspend_fence_addr; mes_suspend_gang_pkt.suspend_fence_value = input->suspend_fence_value; + mes_suspend_gang_pkt.doorbell_offset = input->doorbell_offset; /* Suspend gang is handled by master MES */ return mes_v12_1_submit_pkt_and_poll_completion(mes, input->xcc_id, AMDGPU_MES_SCHED_PIPE, @@ -504,6 +517,7 @@ static int mes_v12_1_resume_gang(struct amdgpu_mes *mes, mes_resume_gang_pkt.resume_all_gangs = input->resume_all_gangs; mes_resume_gang_pkt.gang_context_addr = input->gang_context_addr; + mes_resume_gang_pkt.doorbell_offset = input->doorbell_offset; /* Resume gang is handled by master MES */ return mes_v12_1_submit_pkt_and_poll_completion(mes, input->xcc_id, AMDGPU_MES_SCHED_PIPE, @@ -2260,6 +2274,7 @@ static int mes_v12_1_test_queue(struct amdgpu_device *adev, int xcc_id, remove_queue.xcc_id = xcc_id; remove_queue.doorbell_offset = doorbell_idx; remove_queue.gang_context_addr = add_queue.gang_context_addr; + remove_queue.queue_type = queue_type; r = mes_v12_1_remove_hw_queue(&adev->mes, &remove_queue); error: diff --git a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c index cc688ae79e84..47d07cd25fc4 100644 --- a/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c +++ b/drivers/gpu/drm/amd/amdgpu/mmhub_v1_8.c @@ -29,7 +29,6 @@ #include "soc15_common.h" #include "soc15.h" -#include "amdgpu_ras.h" #include "amdgpu_psp.h" #define regVM_L2_CNTL3_DEFAULT 0x80100007 @@ -636,236 +635,8 @@ const struct amdgpu_mmhub_funcs mmhub_v1_8_funcs = { .get_clockgating = mmhub_v1_8_get_clockgating, }; -static const struct amdgpu_ras_err_status_reg_entry mmhub_v1_8_ce_reg_list[] = { - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA0_CE_ERR_STATUS_LO, regMMEA0_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA0"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA1_CE_ERR_STATUS_LO, regMMEA1_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA1"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA2_CE_ERR_STATUS_LO, regMMEA2_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA2"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA3_CE_ERR_STATUS_LO, regMMEA3_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA3"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA4_CE_ERR_STATUS_LO, regMMEA4_CE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA4"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMM_CANE_CE_ERR_STATUS_LO, regMM_CANE_CE_ERR_STATUS_HI), - 1, 0, "MM_CANE"}, -}; - -static const struct amdgpu_ras_err_status_reg_entry mmhub_v1_8_ue_reg_list[] = { - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA0_UE_ERR_STATUS_LO, regMMEA0_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA0"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA1_UE_ERR_STATUS_LO, regMMEA1_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA1"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA2_UE_ERR_STATUS_LO, regMMEA2_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA2"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA3_UE_ERR_STATUS_LO, regMMEA3_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA3"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMMEA4_UE_ERR_STATUS_LO, regMMEA4_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "MMEA4"}, - {AMDGPU_RAS_REG_ENTRY(MMHUB, 0, regMM_CANE_UE_ERR_STATUS_LO, regMM_CANE_UE_ERR_STATUS_HI), - 1, 0, "MM_CANE"}, -}; - -static const struct amdgpu_ras_memory_id_entry mmhub_v1_8_ras_memory_list[] = { - {AMDGPU_MMHUB_WGMI_PAGEMEM, "MMEA_WGMI_PAGEMEM"}, - {AMDGPU_MMHUB_RGMI_PAGEMEM, "MMEA_RGMI_PAGEMEM"}, - {AMDGPU_MMHUB_WDRAM_PAGEMEM, "MMEA_WDRAM_PAGEMEM"}, - {AMDGPU_MMHUB_RDRAM_PAGEMEM, "MMEA_RDRAM_PAGEMEM"}, - {AMDGPU_MMHUB_WIO_CMDMEM, "MMEA_WIO_CMDMEM"}, - {AMDGPU_MMHUB_RIO_CMDMEM, "MMEA_RIO_CMDMEM"}, - {AMDGPU_MMHUB_WGMI_CMDMEM, "MMEA_WGMI_CMDMEM"}, - {AMDGPU_MMHUB_RGMI_CMDMEM, "MMEA_RGMI_CMDMEM"}, - {AMDGPU_MMHUB_WDRAM_CMDMEM, "MMEA_WDRAM_CMDMEM"}, - {AMDGPU_MMHUB_RDRAM_CMDMEM, "MMEA_RDRAM_CMDMEM"}, - {AMDGPU_MMHUB_MAM_DMEM0, "MMEA_MAM_DMEM0"}, - {AMDGPU_MMHUB_MAM_DMEM1, "MMEA_MAM_DMEM1"}, - {AMDGPU_MMHUB_MAM_DMEM2, "MMEA_MAM_DMEM2"}, - {AMDGPU_MMHUB_MAM_DMEM3, "MMEA_MAM_DMEM3"}, - {AMDGPU_MMHUB_WRET_TAGMEM, "MMEA_WRET_TAGMEM"}, - {AMDGPU_MMHUB_RRET_TAGMEM, "MMEA_RRET_TAGMEM"}, - {AMDGPU_MMHUB_WIO_DATAMEM, "MMEA_WIO_DATAMEM"}, - {AMDGPU_MMHUB_WGMI_DATAMEM, "MMEA_WGMI_DATAMEM"}, - {AMDGPU_MMHUB_WDRAM_DATAMEM, "MMEA_WDRAM_DATAMEM"}, -}; - -static void mmhub_v1_8_inst_query_ras_error_count(struct amdgpu_device *adev, - uint32_t mmhub_inst, - void *ras_err_status) -{ - struct ras_err_data *err_data = (struct ras_err_data *)ras_err_status; - unsigned long ue_count = 0, ce_count = 0; - - /* NOTE: mmhub is converted by aid_mask and the range is 0-3, - * which can be used as die ID directly */ - struct amdgpu_smuio_mcm_config_info mcm_info = { - .socket_id = adev->smuio.funcs->get_socket_id(adev), - .die_id = mmhub_inst, - }; - - amdgpu_ras_inst_query_ras_error_count(adev, - mmhub_v1_8_ce_reg_list, - ARRAY_SIZE(mmhub_v1_8_ce_reg_list), - mmhub_v1_8_ras_memory_list, - ARRAY_SIZE(mmhub_v1_8_ras_memory_list), - mmhub_inst, - AMDGPU_RAS_ERROR__SINGLE_CORRECTABLE, - &ce_count); - amdgpu_ras_inst_query_ras_error_count(adev, - mmhub_v1_8_ue_reg_list, - ARRAY_SIZE(mmhub_v1_8_ue_reg_list), - mmhub_v1_8_ras_memory_list, - ARRAY_SIZE(mmhub_v1_8_ras_memory_list), - mmhub_inst, - AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE, - &ue_count); - - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, ce_count); - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); -} - -static void mmhub_v1_8_query_ras_error_count(struct amdgpu_device *adev, - void *ras_err_status) -{ - uint32_t inst_mask; - uint32_t i; - - if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__MMHUB)) { - dev_warn(adev->dev, "MMHUB RAS is not supported\n"); - return; - } - - inst_mask = adev->aid_mask; - for_each_inst(i, inst_mask) - mmhub_v1_8_inst_query_ras_error_count(adev, i, ras_err_status); -} - -static void mmhub_v1_8_inst_reset_ras_error_count(struct amdgpu_device *adev, - uint32_t mmhub_inst) -{ - amdgpu_ras_inst_reset_ras_error_count(adev, - mmhub_v1_8_ce_reg_list, - ARRAY_SIZE(mmhub_v1_8_ce_reg_list), - mmhub_inst); - amdgpu_ras_inst_reset_ras_error_count(adev, - mmhub_v1_8_ue_reg_list, - ARRAY_SIZE(mmhub_v1_8_ue_reg_list), - mmhub_inst); -} - -static void mmhub_v1_8_reset_ras_error_count(struct amdgpu_device *adev) -{ - uint32_t inst_mask; - uint32_t i; - - if (!amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__MMHUB)) { - dev_warn(adev->dev, "MMHUB RAS is not supported\n"); - return; - } - - inst_mask = adev->aid_mask; - for_each_inst(i, inst_mask) - mmhub_v1_8_inst_reset_ras_error_count(adev, i); -} - -static const struct amdgpu_ras_block_hw_ops mmhub_v1_8_ras_hw_ops = { - .query_ras_error_count = mmhub_v1_8_query_ras_error_count, - .reset_ras_error_count = mmhub_v1_8_reset_ras_error_count, -}; - -static int mmhub_v1_8_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct aca_bank_info info; - u64 misc0; - int ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - misc0 = bank->regs[ACA_REG_IDX_MISC0]; - switch (type) { - case ACA_SMU_TYPE_UE: - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, - 1ULL); - break; - case ACA_SMU_TYPE_CE: - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, - ACA_REG__MISC0__ERRCNT(misc0)); - break; - default: - return -EINVAL; - } - - return ret; -} - -/* reference to smu driver if header file */ -static int mmhub_v1_8_err_codes[] = { - 0, 1, 2, 3, 4, /* CODE_DAGB0 - 4 */ - 5, 6, 7, 8, 9, /* CODE_EA0 - 4 */ - 10, /* CODE_UTCL2_ROUTER */ - 11, /* CODE_VML2 */ - 12, /* CODE_VML2_WALKER */ - 13, /* CODE_MMCANE */ -}; - -static bool mmhub_v1_8_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - u32 instlo; - - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - - if (instlo != mmSMNAID_AID0_MCA_SMU) - return false; - - if (aca_bank_check_error_codes(handle->adev, bank, - mmhub_v1_8_err_codes, - ARRAY_SIZE(mmhub_v1_8_err_codes))) - return false; - - return true; -} - -static const struct aca_bank_ops mmhub_v1_8_aca_bank_ops = { - .aca_bank_parser = mmhub_v1_8_aca_bank_parser, - .aca_bank_is_valid = mmhub_v1_8_aca_bank_is_valid, -}; - -static const struct aca_info mmhub_v1_8_aca_info = { - .hwip = ACA_HWIP_TYPE_SMU, - .mask = ACA_ERROR_UE_MASK, - .bank_ops = &mmhub_v1_8_aca_bank_ops, -}; - -static int mmhub_v1_8_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) -{ - int r; - - r = amdgpu_ras_block_late_init(adev, ras_block); - if (r) - return r; - - r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__MMHUB, - &mmhub_v1_8_aca_info, NULL); - if (r) - goto late_fini; - - return 0; - -late_fini: - amdgpu_ras_block_late_fini(adev, ras_block); - - return r; -} - struct amdgpu_mmhub_ras mmhub_v1_8_ras = { .ras_block = { - .hw_ops = &mmhub_v1_8_ras_hw_ops, - .ras_late_init = mmhub_v1_8_ras_late_init, + .hw_ops = NULL, }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/nv.c b/drivers/gpu/drm/amd/amdgpu/nv.c index 72edf5326b05..77557ee3ca16 100644 --- a/drivers/gpu/drm/amd/amdgpu/nv.c +++ b/drivers/gpu/drm/amd/amdgpu/nv.c @@ -507,11 +507,6 @@ void nv_set_virt_ops(struct amdgpu_device *adev) adev->virt.ops = &xgpu_nv_virt_ops; } -static bool nv_need_full_reset(struct amdgpu_device *adev) -{ - return true; -} - static bool nv_need_reset_on_init(struct amdgpu_device *adev) { u32 sol_reg; @@ -595,7 +590,6 @@ static const struct amdgpu_asic_funcs nv_asic_funcs = { .set_vce_clocks = &nv_set_vce_clocks, .get_config_memsize = &nv_get_config_memsize, .init_doorbell_index = &nv_init_doorbell_index, - .need_full_reset = &nv_need_full_reset, .need_reset_on_init = &nv_need_reset_on_init, .get_pcie_replay_count = &amdgpu_nbio_get_pcie_replay_count, .supports_baco = &amdgpu_dpm_is_baco_supported, diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c index 2a8582e87f2b..2a4d91368ac6 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c @@ -33,6 +33,8 @@ MODULE_FIRMWARE("amdgpu/psp_15_0_0_toc.bin"); MODULE_FIRMWARE("amdgpu/psp_15_0_0_ta.bin"); +MODULE_FIRMWARE("amdgpu/psp_15_0_9_toc.bin"); +MODULE_FIRMWARE("amdgpu/psp_15_0_9_ta.bin"); static int psp_v15_0_0_init_microcode(struct psp_context *psp) { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 3fde9be74690..c2d098cd72ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -1237,65 +1237,6 @@ static int sdma_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block) return -ETIMEDOUT; } -static bool sdma_v3_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 srbm_soft_reset = 0; - u32 tmp = RREG32(mmSRBM_STATUS2); - - if ((tmp & SRBM_STATUS2__SDMA_BUSY_MASK) || - (tmp & SRBM_STATUS2__SDMA1_BUSY_MASK)) { - srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA_MASK; - srbm_soft_reset |= SRBM_SOFT_RESET__SOFT_RESET_SDMA1_MASK; - } - - if (srbm_soft_reset) { - adev->sdma.srbm_soft_reset = srbm_soft_reset; - return true; - } else { - adev->sdma.srbm_soft_reset = 0; - return false; - } -} - -static int sdma_v3_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 srbm_soft_reset = 0; - - if (!adev->sdma.srbm_soft_reset) - return 0; - - srbm_soft_reset = adev->sdma.srbm_soft_reset; - - if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) || - REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) { - sdma_v3_0_ctx_switch_enable(adev, false); - sdma_v3_0_enable(adev, false); - } - - return 0; -} - -static int sdma_v3_0_post_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 srbm_soft_reset = 0; - - if (!adev->sdma.srbm_soft_reset) - return 0; - - srbm_soft_reset = adev->sdma.srbm_soft_reset; - - if (REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA) || - REG_GET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_SDMA1)) { - sdma_v3_0_gfx_resume(adev); - sdma_v3_0_rlc_resume(adev); - } - - return 0; -} - static int sdma_v3_0_soft_reset(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -1552,9 +1493,6 @@ static const struct amd_ip_funcs sdma_v3_0_ip_funcs = { .resume = sdma_v3_0_resume, .is_idle = sdma_v3_0_is_idle, .wait_for_idle = sdma_v3_0_wait_for_idle, - .check_soft_reset = sdma_v3_0_check_soft_reset, - .pre_soft_reset = sdma_v3_0_pre_soft_reset, - .post_soft_reset = sdma_v3_0_post_soft_reset, .soft_reset = sdma_v3_0_soft_reset, .set_clockgating_state = sdma_v3_0_set_clockgating_state, .set_powergating_state = sdma_v3_0_set_powergating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c index 88428b88e00f..484f1a6b5fbc 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v4_4_2.c @@ -95,8 +95,6 @@ static const struct amdgpu_hwip_reg_entry sdma_reg_list_4_4_2[] = { SOC15_REG_ENTRY_STR(GC, 0, regSDMA_VM_CNTL) }; -#define mmSMNAID_AID0_MCA_SMU 0x03b30400 - #define WREG32_SDMA(instance, offset, value) \ WREG32(sdma_v4_4_2_get_reg_offset(adev, (instance), (offset)), value) #define RREG32_SDMA(instance, offset) \ @@ -457,7 +455,7 @@ static void sdma_v4_4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 /* write the fence */ amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -467,7 +465,7 @@ static void sdma_v4_4_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 addr += 4; amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE)); /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(seq)); @@ -1359,6 +1357,19 @@ static int sdma_v4_4_2_early_init(struct amdgpu_ip_block *ip_block) struct amdgpu_device *adev = ip_block->adev; int r; + switch (amdgpu_user_queue) { + case -1: + case 0: + default: + adev->sdma.no_user_submission = false; + adev->sdma.disable_uq = true; + break; + case 2: + adev->sdma.no_user_submission = true; + adev->sdma.disable_uq = true; + break; + } + r = sdma_v4_4_2_init_microcode(adev); if (r) return r; @@ -1478,6 +1489,7 @@ static int sdma_v4_4_2_sw_init(struct amdgpu_ip_block *ip_block) /* doorbell size is 2 dwords, get DWORD offset */ ring->doorbell_index = adev->doorbell_index.sdma_engine[i] << 1; ring->vm_hub = AMDGPU_MMHUB0(aid_id); + ring->no_user_submission = adev->sdma.no_user_submission; sprintf(ring->name, "sdma%d.%d", aid_id, i % adev->sdma.num_inst_per_aid); @@ -2404,187 +2416,9 @@ struct amdgpu_xcp_ip_funcs sdma_v4_4_2_xcp_funcs = { .resume = &sdma_v4_4_2_xcp_resume }; -static const struct amdgpu_ras_err_status_reg_entry sdma_v4_2_2_ue_reg_list[] = { - {AMDGPU_RAS_REG_ENTRY(SDMA0, 0, regSDMA_UE_ERR_STATUS_LO, regSDMA_UE_ERR_STATUS_HI), - 1, (AMDGPU_RAS_ERR_INFO_VALID | AMDGPU_RAS_ERR_STATUS_VALID), "SDMA"}, -}; - -static const struct amdgpu_ras_memory_id_entry sdma_v4_4_2_ras_memory_list[] = { - {AMDGPU_SDMA_MBANK_DATA_BUF0, "SDMA_MBANK_DATA_BUF0"}, - {AMDGPU_SDMA_MBANK_DATA_BUF1, "SDMA_MBANK_DATA_BUF1"}, - {AMDGPU_SDMA_MBANK_DATA_BUF2, "SDMA_MBANK_DATA_BUF2"}, - {AMDGPU_SDMA_MBANK_DATA_BUF3, "SDMA_MBANK_DATA_BUF3"}, - {AMDGPU_SDMA_MBANK_DATA_BUF4, "SDMA_MBANK_DATA_BUF4"}, - {AMDGPU_SDMA_MBANK_DATA_BUF5, "SDMA_MBANK_DATA_BUF5"}, - {AMDGPU_SDMA_MBANK_DATA_BUF6, "SDMA_MBANK_DATA_BUF6"}, - {AMDGPU_SDMA_MBANK_DATA_BUF7, "SDMA_MBANK_DATA_BUF7"}, - {AMDGPU_SDMA_MBANK_DATA_BUF8, "SDMA_MBANK_DATA_BUF8"}, - {AMDGPU_SDMA_MBANK_DATA_BUF9, "SDMA_MBANK_DATA_BUF9"}, - {AMDGPU_SDMA_MBANK_DATA_BUF10, "SDMA_MBANK_DATA_BUF10"}, - {AMDGPU_SDMA_MBANK_DATA_BUF11, "SDMA_MBANK_DATA_BUF11"}, - {AMDGPU_SDMA_MBANK_DATA_BUF12, "SDMA_MBANK_DATA_BUF12"}, - {AMDGPU_SDMA_MBANK_DATA_BUF13, "SDMA_MBANK_DATA_BUF13"}, - {AMDGPU_SDMA_MBANK_DATA_BUF14, "SDMA_MBANK_DATA_BUF14"}, - {AMDGPU_SDMA_MBANK_DATA_BUF15, "SDMA_MBANK_DATA_BUF15"}, - {AMDGPU_SDMA_UCODE_BUF, "SDMA_UCODE_BUF"}, - {AMDGPU_SDMA_RB_CMD_BUF, "SDMA_RB_CMD_BUF"}, - {AMDGPU_SDMA_IB_CMD_BUF, "SDMA_IB_CMD_BUF"}, - {AMDGPU_SDMA_UTCL1_RD_FIFO, "SDMA_UTCL1_RD_FIFO"}, - {AMDGPU_SDMA_UTCL1_RDBST_FIFO, "SDMA_UTCL1_RDBST_FIFO"}, - {AMDGPU_SDMA_UTCL1_WR_FIFO, "SDMA_UTCL1_WR_FIFO"}, - {AMDGPU_SDMA_DATA_LUT_FIFO, "SDMA_DATA_LUT_FIFO"}, - {AMDGPU_SDMA_SPLIT_DAT_BUF, "SDMA_SPLIT_DAT_BUF"}, -}; - -static void sdma_v4_4_2_inst_query_ras_error_count(struct amdgpu_device *adev, - uint32_t sdma_inst, - void *ras_err_status) -{ - struct ras_err_data *err_data = (struct ras_err_data *)ras_err_status; - uint32_t sdma_dev_inst = GET_INST(SDMA0, sdma_inst); - unsigned long ue_count = 0; - struct amdgpu_smuio_mcm_config_info mcm_info = { - .socket_id = adev->smuio.funcs->get_socket_id(adev), - .die_id = adev->sdma.instance[sdma_inst].aid_id, - }; - - /* sdma v4_4_2 doesn't support query ce counts */ - amdgpu_ras_inst_query_ras_error_count(adev, - sdma_v4_2_2_ue_reg_list, - ARRAY_SIZE(sdma_v4_2_2_ue_reg_list), - sdma_v4_4_2_ras_memory_list, - ARRAY_SIZE(sdma_v4_4_2_ras_memory_list), - sdma_dev_inst, - AMDGPU_RAS_ERROR__MULTI_UNCORRECTABLE, - &ue_count); - - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); -} - -static void sdma_v4_4_2_query_ras_error_count(struct amdgpu_device *adev, - void *ras_err_status) -{ - uint32_t inst_mask; - int i = 0; - - inst_mask = GENMASK(adev->sdma.num_instances - 1, 0); - if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) { - for_each_inst(i, inst_mask) - sdma_v4_4_2_inst_query_ras_error_count(adev, i, ras_err_status); - } else { - dev_warn(adev->dev, "SDMA RAS is not supported\n"); - } -} - -static void sdma_v4_4_2_inst_reset_ras_error_count(struct amdgpu_device *adev, - uint32_t sdma_inst) -{ - uint32_t sdma_dev_inst = GET_INST(SDMA0, sdma_inst); - - amdgpu_ras_inst_reset_ras_error_count(adev, - sdma_v4_2_2_ue_reg_list, - ARRAY_SIZE(sdma_v4_2_2_ue_reg_list), - sdma_dev_inst); -} - -static void sdma_v4_4_2_reset_ras_error_count(struct amdgpu_device *adev) -{ - uint32_t inst_mask; - int i = 0; - - inst_mask = GENMASK(adev->sdma.num_instances - 1, 0); - if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__SDMA)) { - for_each_inst(i, inst_mask) - sdma_v4_4_2_inst_reset_ras_error_count(adev, i); - } else { - dev_warn(adev->dev, "SDMA RAS is not supported\n"); - } -} - -static const struct amdgpu_ras_block_hw_ops sdma_v4_4_2_ras_hw_ops = { - .query_ras_error_count = sdma_v4_4_2_query_ras_error_count, - .reset_ras_error_count = sdma_v4_4_2_reset_ras_error_count, -}; - -static int sdma_v4_4_2_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct aca_bank_info info; - u64 misc0; - int ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - misc0 = bank->regs[ACA_REG_IDX_MISC0]; - switch (type) { - case ACA_SMU_TYPE_UE: - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, - 1ULL); - break; - case ACA_SMU_TYPE_CE: - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, - ACA_REG__MISC0__ERRCNT(misc0)); - break; - default: - return -EINVAL; - } - - return ret; -} - -/* CODE_SDMA0 - CODE_SDMA4, reference to smu driver if header file */ -static int sdma_v4_4_2_err_codes[] = { 33, 34, 35, 36 }; - -static bool sdma_v4_4_2_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - u32 instlo; - - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - - if (instlo != mmSMNAID_AID0_MCA_SMU) - return false; - - if (aca_bank_check_error_codes(handle->adev, bank, - sdma_v4_4_2_err_codes, - ARRAY_SIZE(sdma_v4_4_2_err_codes))) - return false; - - return true; -} - -static const struct aca_bank_ops sdma_v4_4_2_aca_bank_ops = { - .aca_bank_parser = sdma_v4_4_2_aca_bank_parser, - .aca_bank_is_valid = sdma_v4_4_2_aca_bank_is_valid, -}; - -static const struct aca_info sdma_v4_4_2_aca_info = { - .hwip = ACA_HWIP_TYPE_SMU, - .mask = ACA_ERROR_UE_MASK, - .bank_ops = &sdma_v4_4_2_aca_bank_ops, -}; - -static int sdma_v4_4_2_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) -{ - int r; - - r = amdgpu_sdma_ras_late_init(adev, ras_block); - if (r) - return r; - - return amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__SDMA, - &sdma_v4_4_2_aca_info, NULL); -} - static struct amdgpu_sdma_ras sdma_v4_4_2_ras = { .ras_block = { - .hw_ops = &sdma_v4_4_2_ras_hw_ops, - .ras_late_init = sdma_v4_4_2_ras_late_init, + .hw_ops = NULL, }, }; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c index fa02907217e0..b809942b1eb7 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c @@ -527,7 +527,7 @@ static void sdma_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -538,7 +538,7 @@ static void sdma_v5_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(seq)); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c index f6ecbc524c9b..87c1e29fd298 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c @@ -377,7 +377,7 @@ static void sdma_v5_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -388,7 +388,7 @@ static void sdma_v5_2_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(seq)); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c index d894b7599c18..7a3f1a60b014 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c @@ -361,7 +361,7 @@ static void sdma_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -372,7 +372,7 @@ static void sdma_v6_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(seq)); @@ -793,23 +793,6 @@ static int sdma_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) return sdma_v6_0_start(adev); } -static bool sdma_v6_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - struct amdgpu_ring *ring; - int i, r; - long tmo = msecs_to_jiffies(1000); - - for (i = 0; i < adev->sdma.num_instances; i++) { - ring = &adev->sdma.instance[i].ring; - r = amdgpu_ring_test_ib(ring, tmo); - if (r) - return true; - } - - return false; -} - /** * sdma_v6_0_start - setup and start the async dma engines * @@ -1747,7 +1730,6 @@ const struct amd_ip_funcs sdma_v6_0_ip_funcs = { .is_idle = sdma_v6_0_is_idle, .wait_for_idle = sdma_v6_0_wait_for_idle, .soft_reset = sdma_v6_0_soft_reset, - .check_soft_reset = sdma_v6_0_check_soft_reset, .set_clockgating_state = sdma_v6_0_set_clockgating_state, .set_powergating_state = sdma_v6_0_set_powergating_state, .get_clockgating_state = sdma_v6_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c index f154b68dda70..84305b6800fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_0.c @@ -363,7 +363,7 @@ static void sdma_v7_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -374,7 +374,7 @@ static void sdma_v7_0_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(seq)); @@ -784,23 +784,6 @@ static int sdma_v7_0_soft_reset(struct amdgpu_ip_block *ip_block) return sdma_v7_0_start(adev); } -static bool sdma_v7_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - struct amdgpu_ring *ring; - int i, r; - long tmo = msecs_to_jiffies(1000); - - for (i = 0; i < adev->sdma.num_instances; i++) { - ring = &adev->sdma.instance[i].ring; - r = amdgpu_ring_test_ib(ring, tmo); - if (r) - return true; - } - - return false; -} - static int sdma_v7_0_reset_queue(struct amdgpu_ring *ring, unsigned int vmid, struct amdgpu_fence *timedout_fence) @@ -1679,7 +1662,6 @@ const struct amd_ip_funcs sdma_v7_0_ip_funcs = { .is_idle = sdma_v7_0_is_idle, .wait_for_idle = sdma_v7_0_wait_for_idle, .soft_reset = sdma_v7_0_soft_reset, - .check_soft_reset = sdma_v7_0_check_soft_reset, .set_clockgating_state = sdma_v7_0_set_clockgating_state, .set_powergating_state = sdma_v7_0_set_powergating_state, .get_clockgating_state = sdma_v7_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c index cd9668605a50..322e6f4dd121 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v7_1.c @@ -331,7 +331,7 @@ static void sdma_v7_1_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* Ucached(UC) */ /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, lower_32_bits(seq)); @@ -342,7 +342,7 @@ static void sdma_v7_1_ring_emit_fence(struct amdgpu_ring *ring, u64 addr, u64 se amdgpu_ring_write(ring, SDMA_PKT_COPY_LINEAR_HEADER_OP(SDMA_OP_FENCE) | SDMA_PKT_FENCE_HEADER_MTYPE(0x3)); /* zero in first two bits */ - BUG_ON(addr & 0x3); + WARN_ON(addr & 0x3); amdgpu_ring_write(ring, lower_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(addr)); amdgpu_ring_write(ring, upper_32_bits(seq)); @@ -775,23 +775,6 @@ static int sdma_v7_1_soft_reset(struct amdgpu_ip_block *ip_block) return sdma_v7_1_inst_start(adev, inst_mask); } -static bool sdma_v7_1_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - struct amdgpu_ring *ring; - int i, r; - long tmo = msecs_to_jiffies(1000); - - for (i = 0; i < adev->sdma.num_instances; i++) { - ring = &adev->sdma.instance[i].ring; - r = amdgpu_ring_test_ib(ring, tmo); - if (r) - return true; - } - - return false; -} - static int sdma_v7_1_reset_queue(struct amdgpu_ring *ring, unsigned int vmid, struct amdgpu_fence *timedout_fence) @@ -1644,7 +1627,6 @@ const struct amd_ip_funcs sdma_v7_1_ip_funcs = { .is_idle = sdma_v7_1_is_idle, .wait_for_idle = sdma_v7_1_wait_for_idle, .soft_reset = sdma_v7_1_soft_reset, - .check_soft_reset = sdma_v7_1_check_soft_reset, .set_clockgating_state = sdma_v7_1_set_clockgating_state, .set_powergating_state = sdma_v7_1_set_powergating_state, .get_clockgating_state = sdma_v7_1_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index c26cb3e8bff6..b104469c38ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1509,12 +1509,6 @@ static void si_invalidate_hdp(struct amdgpu_device *adev, } } -static bool si_need_full_reset(struct amdgpu_device *adev) -{ - /* change this when we support soft reset */ - return true; -} - static bool si_need_reset_on_init(struct amdgpu_device *adev) { return false; @@ -2019,7 +2013,6 @@ static const struct amdgpu_asic_funcs si_asic_funcs = .get_config_memsize = &si_get_config_memsize, .flush_hdp = &si_flush_hdp, .invalidate_hdp = &si_invalidate_hdp, - .need_full_reset = &si_need_full_reset, .get_pcie_usage = &si_get_pcie_usage, .need_reset_on_init = &si_need_reset_on_init, .get_pcie_replay_count = &si_get_pcie_replay_count, diff --git a/drivers/gpu/drm/amd/amdgpu/soc15.c b/drivers/gpu/drm/amd/amdgpu/soc15.c index 87b398dd0769..ed3fd58b78d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15.c +++ b/drivers/gpu/drm/amd/amdgpu/soc15.c @@ -721,12 +721,6 @@ void soc15_set_virt_ops(struct amdgpu_device *adev) soc15_reg_base_init(adev); } -static bool soc15_need_full_reset(struct amdgpu_device *adev) -{ - /* change this when we implement soft reset */ - return true; -} - static void soc15_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0, uint64_t *count1) { @@ -878,7 +872,6 @@ static const struct amdgpu_asic_funcs soc15_asic_funcs = .set_uvd_clocks = &soc15_set_uvd_clocks, .set_vce_clocks = &soc15_set_vce_clocks, .get_config_memsize = &soc15_get_config_memsize, - .need_full_reset = &soc15_need_full_reset, .init_doorbell_index = &vega10_doorbell_index_init, .get_pcie_usage = &soc15_get_pcie_usage, .need_reset_on_init = &soc15_need_reset_on_init, @@ -899,7 +892,6 @@ static const struct amdgpu_asic_funcs vega20_asic_funcs = .set_uvd_clocks = &soc15_set_uvd_clocks, .set_vce_clocks = &soc15_set_vce_clocks, .get_config_memsize = &soc15_get_config_memsize, - .need_full_reset = &soc15_need_full_reset, .init_doorbell_index = &vega20_doorbell_index_init, .get_pcie_usage = &vega20_get_pcie_usage, .need_reset_on_init = &soc15_need_reset_on_init, @@ -920,7 +912,6 @@ static const struct amdgpu_asic_funcs aqua_vanjaram_asic_funcs = .set_uvd_clocks = &soc15_set_uvd_clocks, .set_vce_clocks = &soc15_set_vce_clocks, .get_config_memsize = &soc15_get_config_memsize, - .need_full_reset = &soc15_need_full_reset, .init_doorbell_index = &aqua_vanjaram_doorbell_index_init, .need_reset_on_init = &soc15_need_reset_on_init, .get_pcie_replay_count = &amdgpu_nbio_get_pcie_replay_count, diff --git a/drivers/gpu/drm/amd/amdgpu/soc15_common.h b/drivers/gpu/drm/amd/amdgpu/soc15_common.h index a7b5a95ebebb..47e0329b6f3f 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc15_common.h +++ b/drivers/gpu/drm/amd/amdgpu/soc15_common.h @@ -38,30 +38,30 @@ (adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + (reg)+(offset)) #define __WREG32_SOC15_RLC__(reg, value, flag, hwip, inst) \ - ((amdgpu_sriov_vf(adev) && adev->gfx.rlc.funcs && adev->gfx.rlc.rlcg_reg_access_supported) ? \ - amdgpu_sriov_wreg(adev, reg, value, flag, hwip, inst) : \ - WREG32(reg, value)) + adev->gfx.rlc.reg_funcs->wreg32(adev, reg, value, flag, hwip, inst) #define __RREG32_SOC15_RLC__(reg, flag, hwip, inst) \ - ((amdgpu_sriov_vf(adev) && adev->gfx.rlc.funcs && adev->gfx.rlc.rlcg_reg_access_supported) ? \ - amdgpu_sriov_rreg(adev, reg, flag, hwip, inst) : \ - RREG32(reg)) + adev->gfx.rlc.reg_funcs->rreg32(adev, reg, flag, hwip, inst) -#define WREG32_FIELD15(ip, idx, reg, field, val) \ - __WREG32_SOC15_RLC__(adev->reg_offset[ip##_HWIP][idx][mm##reg##_BASE_IDX] + mm##reg, \ - (__RREG32_SOC15_RLC__( \ - adev->reg_offset[ip##_HWIP][idx][mm##reg##_BASE_IDX] + mm##reg, \ - 0, ip##_HWIP, idx) & \ - ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field), \ - 0, ip##_HWIP, idx) +#define WREG32_FIELD15(ip, idx, reg_name, field, val) \ +do { \ + u32 reg__ = adev->reg_offset[ip##_HWIP][idx][mm##reg_name##_BASE_IDX] + mm##reg_name; \ + u32 val__ = __RREG32_SOC15_RLC__(reg__, 0, ip##_HWIP, idx); \ +\ + val__ &= ~REG_FIELD_MASK(reg_name, field); \ + val__ |= (val) << REG_FIELD_SHIFT(reg_name, field); \ + __WREG32_SOC15_RLC__(reg__, val__, 0, ip##_HWIP, idx); \ +} while (0) -#define WREG32_FIELD15_PREREG(ip, idx, reg_name, field, val) \ - __WREG32_SOC15_RLC__(adev->reg_offset[ip##_HWIP][idx][reg##reg_name##_BASE_IDX] + reg##reg_name, \ - (__RREG32_SOC15_RLC__( \ - adev->reg_offset[ip##_HWIP][idx][reg##reg_name##_BASE_IDX] + reg##reg_name, \ - 0, ip##_HWIP, idx) & \ - ~REG_FIELD_MASK(reg_name, field)) | (val) << REG_FIELD_SHIFT(reg_name, field), \ - 0, ip##_HWIP, idx) +#define WREG32_FIELD15_PREREG(ip, idx, reg_name, field, val) \ +do { \ + u32 reg__ = adev->reg_offset[ip##_HWIP][idx][reg##reg_name##_BASE_IDX] + reg##reg_name; \ + u32 val__ = __RREG32_SOC15_RLC__(reg__, 0, ip##_HWIP, idx); \ +\ + val__ &= ~REG_FIELD_MASK(reg_name, field); \ + val__ |= (val) << REG_FIELD_SHIFT(reg_name, field); \ + __WREG32_SOC15_RLC__(reg__, val__, 0, ip##_HWIP, idx); \ +} while (0) #define RREG32_SOC15(ip, inst, reg) \ __RREG32_SOC15_RLC__(adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg, \ @@ -181,12 +181,15 @@ WREG32_RLC_EX(prefix, target_reg, value, inst); \ } while (0) -#define WREG32_FIELD15_RLC(ip, idx, reg, field, val) \ - __WREG32_SOC15_RLC__((adev->reg_offset[ip##_HWIP][idx][mm##reg##_BASE_IDX] + mm##reg), \ - (__RREG32_SOC15_RLC__(adev->reg_offset[ip##_HWIP][idx][mm##reg##_BASE_IDX] + mm##reg, \ - AMDGPU_REGS_RLC, ip##_HWIP, idx) & \ - ~REG_FIELD_MASK(reg, field)) | (val) << REG_FIELD_SHIFT(reg, field), \ - AMDGPU_REGS_RLC, ip##_HWIP, idx) +#define WREG32_FIELD15_RLC(ip, idx, reg_name, field, val) \ +do { \ + u32 reg__ = adev->reg_offset[ip##_HWIP][idx][mm##reg_name##_BASE_IDX] + mm##reg_name; \ + u32 val__ = __RREG32_SOC15_RLC__(reg__, AMDGPU_REGS_RLC, ip##_HWIP, idx); \ +\ + val__ &= ~REG_FIELD_MASK(reg_name, field); \ + val__ |= (val) << REG_FIELD_SHIFT(reg_name, field); \ + __WREG32_SOC15_RLC__(reg__, val__, AMDGPU_REGS_RLC, ip##_HWIP, idx); \ +} while (0) #define WREG32_SOC15_OFFSET_RLC(ip, inst, reg, offset, value) \ __WREG32_SOC15_RLC__((adev->reg_offset[ip##_HWIP][inst][reg##_BASE_IDX] + reg) + offset, value, AMDGPU_REGS_RLC, ip##_HWIP, inst) @@ -207,10 +210,4 @@ amdgpu_reg_get_smn_base64(adev, ip##_HWIP, inst), \ value) -#define RREG64_MCA(smn_base, mca_base, idx) \ - RREG64_PCIE_EXT(smn_base + mca_base + (idx * 8)) - -#define WREG64_MCA(smn_base, mca_base, idx, val) \ - WREG64_PCIE_EXT(smn_base + mca_base + (idx * 8), val) - #endif diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 963659deeaff..09f28dbd60ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -461,17 +461,6 @@ const struct amdgpu_ip_block_version soc21_common_ip_block = { .funcs = &soc21_common_ip_funcs, }; -static bool soc21_need_full_reset(struct amdgpu_device *adev) -{ - switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { - case IP_VERSION(11, 0, 0): - case IP_VERSION(11, 0, 2): - case IP_VERSION(11, 0, 3): - default: - return true; - } -} - static bool soc21_need_reset_on_init(struct amdgpu_device *adev) { u32 sol_reg; @@ -550,7 +539,6 @@ static const struct amdgpu_asic_funcs soc21_asic_funcs = { .set_vce_clocks = &soc21_set_vce_clocks, .get_config_memsize = &soc21_get_config_memsize, .init_doorbell_index = &soc21_init_doorbell_index, - .need_full_reset = &soc21_need_full_reset, .need_reset_on_init = &soc21_need_reset_on_init, .get_pcie_replay_count = &amdgpu_nbio_get_pcie_replay_count, .supports_baco = &amdgpu_dpm_is_baco_supported, @@ -838,6 +826,62 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block) adev->pg_flags = 0; adev->external_rev_id = adev->rev_id + 0xd0; break; + case IP_VERSION(11, 7, 0): + adev->cg_flags = AMD_CG_SUPPORT_VCN_MGCG | + AMD_CG_SUPPORT_JPEG_MGCG | + AMD_CG_SUPPORT_GFX_CGCG | + AMD_CG_SUPPORT_GFX_CGLS | + AMD_CG_SUPPORT_GFX_MGCG | + AMD_CG_SUPPORT_GFX_FGCG | + AMD_CG_SUPPORT_REPEATER_FGCG | + AMD_CG_SUPPORT_GFX_PERF_CLK | + AMD_CG_SUPPORT_GFX_3D_CGCG | + AMD_CG_SUPPORT_GFX_3D_CGLS | + AMD_CG_SUPPORT_MC_MGCG | + AMD_CG_SUPPORT_MC_LS | + AMD_CG_SUPPORT_HDP_LS | + AMD_CG_SUPPORT_HDP_DS | + AMD_CG_SUPPORT_HDP_SD | + AMD_CG_SUPPORT_ATHUB_MGCG | + AMD_CG_SUPPORT_ATHUB_LS | + AMD_CG_SUPPORT_IH_CG | + AMD_CG_SUPPORT_BIF_MGCG | + AMD_CG_SUPPORT_BIF_LS; + adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG | + AMD_PG_SUPPORT_VCN | + AMD_PG_SUPPORT_JPEG_DPG | + AMD_PG_SUPPORT_JPEG | + AMD_PG_SUPPORT_GFX_PG; + adev->external_rev_id = adev->rev_id + 0xF; + break; + case IP_VERSION(11, 7, 1): + adev->cg_flags = AMD_CG_SUPPORT_VCN_MGCG | + AMD_CG_SUPPORT_JPEG_MGCG | + AMD_CG_SUPPORT_GFX_CGCG | + AMD_CG_SUPPORT_GFX_CGLS | + AMD_CG_SUPPORT_GFX_MGCG | + AMD_CG_SUPPORT_GFX_FGCG | + AMD_CG_SUPPORT_REPEATER_FGCG | + AMD_CG_SUPPORT_GFX_PERF_CLK | + AMD_CG_SUPPORT_GFX_3D_CGCG | + AMD_CG_SUPPORT_GFX_3D_CGLS | + AMD_CG_SUPPORT_MC_MGCG | + AMD_CG_SUPPORT_MC_LS | + AMD_CG_SUPPORT_HDP_LS | + AMD_CG_SUPPORT_HDP_DS | + AMD_CG_SUPPORT_HDP_SD | + AMD_CG_SUPPORT_ATHUB_MGCG | + AMD_CG_SUPPORT_ATHUB_LS | + AMD_CG_SUPPORT_IH_CG | + AMD_CG_SUPPORT_BIF_MGCG | + AMD_CG_SUPPORT_BIF_LS; + adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG | + AMD_PG_SUPPORT_VCN | + AMD_PG_SUPPORT_JPEG_DPG | + AMD_PG_SUPPORT_JPEG | + AMD_PG_SUPPORT_GFX_PG; + adev->external_rev_id = adev->rev_id + 0x40; + break; default: /* FIXME: not supported yet */ return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/soc24.c b/drivers/gpu/drm/amd/amdgpu/soc24.c index 265db9331d0b..e5e3a460e486 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc24.c +++ b/drivers/gpu/drm/amd/amdgpu/soc24.c @@ -238,16 +238,6 @@ const struct amdgpu_ip_block_version soc24_common_ip_block = { .funcs = &soc24_common_ip_funcs, }; -static bool soc24_need_full_reset(struct amdgpu_device *adev) -{ - switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { - case IP_VERSION(12, 0, 0): - case IP_VERSION(12, 0, 1): - default: - return true; - } -} - static bool soc24_need_reset_on_init(struct amdgpu_device *adev) { u32 sol_reg; @@ -330,7 +320,6 @@ static const struct amdgpu_asic_funcs soc24_asic_funcs = { .get_xclk = &soc24_get_xclk, .get_config_memsize = &soc24_get_config_memsize, .init_doorbell_index = &soc24_init_doorbell_index, - .need_full_reset = &soc24_need_full_reset, .need_reset_on_init = &soc24_need_reset_on_init, .get_pcie_replay_count = &soc24_get_pcie_replay_count, .supports_baco = &amdgpu_dpm_is_baco_supported, @@ -496,8 +485,36 @@ static int soc24_common_suspend(struct amdgpu_ip_block *ip_block) return soc24_common_hw_fini(ip_block); } +static bool soc24_need_reset_on_resume(struct amdgpu_device *adev) +{ + u32 sol_reg1, sol_reg2; + + /* Will reset for the following suspend abort cases. + * 1) Only reset dGPU side. + * 2) S3 suspend got aborted and TOS is active. + * As for dGPU suspend abort cases the SOL value + * will be kept as zero at this resume point. + */ + if (!(adev->flags & AMD_IS_APU) && adev->in_s3) { + sol_reg1 = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_81); + msleep(100); + sol_reg2 = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_81); + + return (sol_reg1 != sol_reg2); + } + + return false; +} + static int soc24_common_resume(struct amdgpu_ip_block *ip_block) { + struct amdgpu_device *adev = ip_block->adev; + + if (soc24_need_reset_on_resume(adev)) { + dev_info(adev->dev, "S3 suspend aborted, resetting..."); + soc24_asic_reset(adev); + } + return soc24_common_hw_init(ip_block); } diff --git a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c index 5f05c8e68297..a9039fb1a77b 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c +++ b/drivers/gpu/drm/amd/amdgpu/soc_v1_0.c @@ -223,15 +223,6 @@ static int soc_v1_0_read_register(struct amdgpu_device *adev, return -EINVAL; } -static bool soc_v1_0_need_full_reset(struct amdgpu_device *adev) -{ - switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { - case IP_VERSION(12, 1, 0): - default: - return true; - } -} - static bool soc_v1_0_need_reset_on_init(struct amdgpu_device *adev) { @@ -271,7 +262,6 @@ static const struct amdgpu_asic_funcs soc_v1_0_asic_funcs = { .read_register = &soc_v1_0_read_register, .get_config_memsize = &soc_v1_0_get_config_memsize, .get_xclk = &soc_v1_0_get_xclk, - .need_full_reset = &soc_v1_0_need_full_reset, .init_doorbell_index = &soc_v1_0_doorbell_index_init, .need_reset_on_init = &soc_v1_0_need_reset_on_init, .encode_ext_smn_addressing = &soc_v1_0_encode_ext_smn_addressing, @@ -600,8 +590,10 @@ static int soc_v1_0_get_xcp_res_info(struct amdgpu_xcp_mgr *xcp_mgr, xcp_cfg->num_res = ARRAY_SIZE(max_res); for (i = 0; i < xcp_cfg->num_res; i++) { - res_lt_xcp = max_res[i] < num_xcp; xcp_cfg->xcp_res[i].id = i; + if (!max_res[i]) + continue; + res_lt_xcp = max_res[i] < num_xcp; xcp_cfg->xcp_res[i].num_inst = res_lt_xcp ? 1 : max_res[i] / num_xcp; xcp_cfg->xcp_res[i].num_inst = diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c index ee8038df17e3..a3e883f6f099 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_ih.c @@ -390,43 +390,6 @@ static int tonga_ih_wait_for_idle(struct amdgpu_ip_block *ip_block) return -ETIMEDOUT; } -static bool tonga_ih_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 srbm_soft_reset = 0; - u32 tmp = RREG32(mmSRBM_STATUS); - - if (tmp & SRBM_STATUS__IH_BUSY_MASK) - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, - SOFT_RESET_IH, 1); - - if (srbm_soft_reset) { - adev->irq.srbm_soft_reset = srbm_soft_reset; - return true; - } else { - adev->irq.srbm_soft_reset = 0; - return false; - } -} - -static int tonga_ih_pre_soft_reset(struct amdgpu_ip_block *ip_block) -{ - if (!ip_block->adev->irq.srbm_soft_reset) - return 0; - - return tonga_ih_hw_fini(ip_block); -} - -static int tonga_ih_post_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - if (!adev->irq.srbm_soft_reset) - return 0; - - return tonga_ih_hw_init(ip_block); -} - static int tonga_ih_soft_reset(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -481,10 +444,7 @@ static const struct amd_ip_funcs tonga_ih_ip_funcs = { .resume = tonga_ih_resume, .is_idle = tonga_ih_is_idle, .wait_for_idle = tonga_ih_wait_for_idle, - .check_soft_reset = tonga_ih_check_soft_reset, - .pre_soft_reset = tonga_ih_pre_soft_reset, .soft_reset = tonga_ih_soft_reset, - .post_soft_reset = tonga_ih_post_soft_reset, .set_clockgating_state = tonga_ih_set_clockgating_state, .set_powergating_state = tonga_ih_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c index 14092150336a..67bdf7303e6b 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.c @@ -28,48 +28,6 @@ #include "umc/umc_12_0_0_sh_mask.h" #include "mp/mp_13_0_6_sh_mask.h" -#define MAX_ECC_NUM_PER_RETIREMENT 32 -#define DELAYED_TIME_FOR_GPU_RESET 1000 //ms - -static inline uint64_t get_umc_v12_0_reg_offset(struct amdgpu_device *adev, - uint32_t node_inst, - uint32_t umc_inst, - uint32_t ch_inst) -{ - uint32_t index = umc_inst * adev->umc.channel_inst_num + ch_inst; - uint64_t cross_node_offset = (node_inst == 0) ? 0 : UMC_V12_0_CROSS_NODE_OFFSET; - - umc_inst = index / 4; - ch_inst = index % 4; - - return adev->umc.channel_offs * ch_inst + UMC_V12_0_INST_DIST * umc_inst + - UMC_V12_0_NODE_DIST * node_inst + cross_node_offset; -} - -static int umc_v12_0_reset_error_count_per_channel(struct amdgpu_device *adev, - uint32_t node_inst, uint32_t umc_inst, - uint32_t ch_inst, void *data) -{ - uint64_t odecc_err_cnt_addr; - uint64_t umc_reg_offset = - get_umc_v12_0_reg_offset(adev, node_inst, umc_inst, ch_inst); - - odecc_err_cnt_addr = - SOC15_REG_OFFSET(UMC, 0, regUMCCH0_OdEccErrCnt); - - /* clear error count */ - WREG32_PCIE_EXT((odecc_err_cnt_addr + umc_reg_offset) * 4, - UMC_V12_0_CE_CNT_INIT); - - return 0; -} - -static void umc_v12_0_reset_error_count(struct amdgpu_device *adev) -{ - amdgpu_umc_loop_channels(adev, - umc_v12_0_reset_error_count_per_channel, NULL); -} - bool umc_v12_0_is_deferred_error(struct amdgpu_device *adev, uint64_t mc_umc_status) { dev_dbg(adev->dev, @@ -115,65 +73,6 @@ bool umc_v12_0_is_correctable_error(struct amdgpu_device *adev, uint64_t mc_umc_ !(umc_v12_0_is_uncorrectable_error(adev, mc_umc_status))))); } -static void umc_v12_0_query_error_count_per_type(struct amdgpu_device *adev, - uint64_t umc_reg_offset, - unsigned long *error_count, - check_error_type_func error_type_func) -{ - uint64_t mc_umc_status; - uint64_t mc_umc_status_addr; - - mc_umc_status_addr = - SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); - - /* Check MCUMC_STATUS */ - mc_umc_status = - RREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4); - - if (error_type_func(adev, mc_umc_status)) - *error_count += 1; -} - -static int umc_v12_0_query_error_count(struct amdgpu_device *adev, - uint32_t node_inst, uint32_t umc_inst, - uint32_t ch_inst, void *data) -{ - struct ras_err_data *err_data = (struct ras_err_data *)data; - unsigned long ue_count = 0, ce_count = 0, de_count = 0; - - /* NOTE: node_inst is converted by adev->umc.active_mask and the range is [0-3], - * which can be used as die ID directly */ - struct amdgpu_smuio_mcm_config_info mcm_info = { - .socket_id = adev->smuio.funcs->get_socket_id(adev), - .die_id = node_inst, - }; - - uint64_t umc_reg_offset = - get_umc_v12_0_reg_offset(adev, node_inst, umc_inst, ch_inst); - - umc_v12_0_query_error_count_per_type(adev, umc_reg_offset, - &ce_count, umc_v12_0_is_correctable_error); - umc_v12_0_query_error_count_per_type(adev, umc_reg_offset, - &ue_count, umc_v12_0_is_uncorrectable_error); - umc_v12_0_query_error_count_per_type(adev, umc_reg_offset, - &de_count, umc_v12_0_is_deferred_error); - - amdgpu_ras_error_statistic_ue_count(err_data, &mcm_info, ue_count); - amdgpu_ras_error_statistic_ce_count(err_data, &mcm_info, ce_count); - amdgpu_ras_error_statistic_de_count(err_data, &mcm_info, de_count); - - return 0; -} - -static void umc_v12_0_query_ras_error_count(struct amdgpu_device *adev, - void *ras_error_status) -{ - amdgpu_umc_loop_channels(adev, - umc_v12_0_query_error_count, ras_error_status); - - umc_v12_0_reset_error_count(adev); -} - static void umc_v12_0_get_retire_flip_bits(struct amdgpu_device *adev) { enum amdgpu_memory_partition nps = AMDGPU_NPS1_PARTITION_MODE; @@ -279,190 +178,6 @@ static void umc_v12_0_get_retire_flip_bits(struct amdgpu_device *adev) adev->umc.retire_unit = 0x1 << flip_bits->bit_num; } -static int umc_v12_0_convert_error_address(struct amdgpu_device *adev, - struct ras_err_data *err_data, - struct ta_ras_query_address_input *addr_in, - struct ta_ras_query_address_output *addr_out, - bool dump_addr) -{ - uint32_t row = 0, row_lower = 0, row_high = 0; - uint32_t col = 0, col_lower = 0, bank = 0; - uint32_t channel_index = 0, umc_inst = 0; - uint32_t i, bit_num, retire_unit, *flip_bits; - uint64_t soc_pa, column, err_addr; - struct ta_ras_query_address_output addr_out_tmp; - struct ta_ras_query_address_output *paddr_out; - int ret = 0; - - if (!addr_out) - paddr_out = &addr_out_tmp; - else - paddr_out = addr_out; - - err_addr = bank = 0; - if (addr_in) { - err_addr = addr_in->ma.err_addr; - addr_in->addr_type = TA_RAS_MCA_TO_PA; - ret = psp_ras_query_address(&adev->psp, addr_in, paddr_out); - if (ret) { - dev_warn(adev->dev, "Failed to query RAS physical address for 0x%llx", - err_addr); - - goto out; - } - - bank = paddr_out->pa.bank; - /* no need to care about umc inst if addr_in is NULL */ - umc_inst = addr_in->ma.umc_inst; - } - - flip_bits = adev->umc.flip_bits.flip_bits_in_pa; - bit_num = adev->umc.flip_bits.bit_num; - retire_unit = adev->umc.retire_unit; - - soc_pa = paddr_out->pa.pa; - channel_index = paddr_out->pa.channel_idx; - /* clear loop bits in soc physical address */ - for (i = 0; i < bit_num; i++) - soc_pa &= ~BIT_ULL(flip_bits[i]); - - paddr_out->pa.pa = soc_pa; - /* get column bit 0 and 1 in mca address */ - col_lower = (err_addr >> 1) & 0x3ULL; - /* extra row bit will be handled later */ - row_lower = (err_addr >> UMC_V12_0_MA_R0_BIT) & 0x1fffULL; - row_lower &= ~BIT_ULL(adev->umc.flip_bits.flip_row_bit); - - if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(9, 5, 0)) { - row_high = (soc_pa >> adev->umc.flip_bits.r13_in_pa) & 0x3ULL; - /* it's 2.25GB in each channel, from MCA address to PA - * [R14 R13] is converted if the two bits value are 0x3, - * get them from PA instead of MCA address. - */ - row_lower |= (row_high << 13); - } - - if (!err_data && !dump_addr) - goto out; - - /* loop for all possibilities of retired bits */ - for (column = 0; column < retire_unit; column++) { - soc_pa = paddr_out->pa.pa; - for (i = 0; i < bit_num; i++) - soc_pa |= (((column >> i) & 0x1ULL) << flip_bits[i]); - - col = ((column & 0x7) << 2) | col_lower; - /* handle extra row bit */ - if (bit_num == RETIRE_FLIP_BITS_NUM) - row = ((column >> 3) << adev->umc.flip_bits.flip_row_bit) | - row_lower; - - if (dump_addr) - dev_info(adev->dev, - "Error Address(PA):0x%-10llx Row:0x%-4x Col:0x%-2x Bank:0x%x Channel:0x%x\n", - soc_pa, row, col, bank, channel_index); - - if (err_data) - amdgpu_umc_fill_error_record(err_data, err_addr, - soc_pa, channel_index, umc_inst); - } - -out: - return ret; -} - -static int umc_v12_0_query_error_address(struct amdgpu_device *adev, - uint32_t node_inst, uint32_t umc_inst, - uint32_t ch_inst, void *data) -{ - struct ras_err_data *err_data = (struct ras_err_data *)data; - struct ta_ras_query_address_input addr_in; - uint64_t mc_umc_status_addr; - uint64_t mc_umc_status, err_addr; - uint64_t mc_umc_addrt0; - uint64_t umc_reg_offset = - get_umc_v12_0_reg_offset(adev, node_inst, umc_inst, ch_inst); - - mc_umc_status_addr = - SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_STATUST0); - - mc_umc_status = RREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4); - - if (mc_umc_status == 0) - return 0; - - if (!err_data->err_addr) { - /* clear umc status */ - WREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); - - return 0; - } - - /* calculate error address if ue error is detected */ - if (umc_v12_0_is_uncorrectable_error(adev, mc_umc_status) || - umc_v12_0_is_deferred_error(adev, mc_umc_status)) { - mc_umc_addrt0 = - SOC15_REG_OFFSET(UMC, 0, regMCA_UMC_UMC0_MCUMC_ADDRT0); - - err_addr = RREG64_PCIE_EXT((mc_umc_addrt0 + umc_reg_offset) * 4); - - err_addr = REG_GET_FIELD(err_addr, MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); - - if (!adev->aid_mask && - adev->smuio.funcs && - adev->smuio.funcs->get_socket_id) - addr_in.ma.socket_id = adev->smuio.funcs->get_socket_id(adev); - else - addr_in.ma.socket_id = 0; - - addr_in.ma.err_addr = err_addr; - addr_in.ma.ch_inst = ch_inst; - addr_in.ma.umc_inst = umc_inst; - addr_in.ma.node_inst = node_inst; - - umc_v12_0_convert_error_address(adev, err_data, &addr_in, NULL, true); - } - - /* clear umc status */ - WREG64_PCIE_EXT((mc_umc_status_addr + umc_reg_offset) * 4, 0x0ULL); - - return 0; -} - -static void umc_v12_0_query_ras_error_address(struct amdgpu_device *adev, - void *ras_error_status) -{ - amdgpu_umc_loop_channels(adev, - umc_v12_0_query_error_address, ras_error_status); -} - -static int umc_v12_0_err_cnt_init_per_channel(struct amdgpu_device *adev, - uint32_t node_inst, uint32_t umc_inst, - uint32_t ch_inst, void *data) -{ - uint32_t odecc_cnt_sel; - uint64_t odecc_cnt_sel_addr, odecc_err_cnt_addr; - uint64_t umc_reg_offset = - get_umc_v12_0_reg_offset(adev, node_inst, umc_inst, ch_inst); - - odecc_cnt_sel_addr = - SOC15_REG_OFFSET(UMC, 0, regUMCCH0_OdEccCntSel); - odecc_err_cnt_addr = - SOC15_REG_OFFSET(UMC, 0, regUMCCH0_OdEccErrCnt); - - odecc_cnt_sel = RREG32_PCIE_EXT((odecc_cnt_sel_addr + umc_reg_offset) * 4); - - /* set ce error interrupt type to APIC based interrupt */ - odecc_cnt_sel = REG_SET_FIELD(odecc_cnt_sel, UMCCH0_OdEccCntSel, - OdEccErrInt, 0x1); - WREG32_PCIE_EXT((odecc_cnt_sel_addr + umc_reg_offset) * 4, odecc_cnt_sel); - - /* set error count to initial value */ - WREG32_PCIE_EXT((odecc_err_cnt_addr + umc_reg_offset) * 4, UMC_V12_0_CE_CNT_INIT); - - return 0; -} - static bool umc_v12_0_check_ecc_err_status(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, void *ras_error_status) { @@ -482,309 +197,11 @@ static bool umc_v12_0_check_ecc_err_status(struct amdgpu_device *adev, return false; } -static void umc_v12_0_err_cnt_init(struct amdgpu_device *adev) -{ - amdgpu_umc_loop_channels(adev, - umc_v12_0_err_cnt_init_per_channel, NULL); -} - -static bool umc_v12_0_query_ras_poison_mode(struct amdgpu_device *adev) -{ - /* - * Force return true, because regUMCCH0_EccCtrl - * is not accessible from host side - */ - return true; -} - -const struct amdgpu_ras_block_hw_ops umc_v12_0_ras_hw_ops = { - .query_ras_error_count = umc_v12_0_query_ras_error_count, - .query_ras_error_address = umc_v12_0_query_ras_error_address, -}; - -static int umc_v12_0_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct amdgpu_device *adev = handle->adev; - struct aca_bank_info info; - enum aca_error_type err_type; - u64 status, count; - u32 ext_error_code; - int ret; - - status = bank->regs[ACA_REG_IDX_STATUS]; - if (umc_v12_0_is_deferred_error(adev, status)) - err_type = ACA_ERROR_TYPE_DEFERRED; - else if (umc_v12_0_is_uncorrectable_error(adev, status)) - err_type = ACA_ERROR_TYPE_UE; - else if (umc_v12_0_is_correctable_error(adev, status)) - err_type = ACA_ERROR_TYPE_CE; - else - return 0; - bank->aca_err_type = err_type; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - amdgpu_umc_update_ecc_status(adev, - bank->regs[ACA_REG_IDX_STATUS], - bank->regs[ACA_REG_IDX_IPID], - bank->regs[ACA_REG_IDX_ADDR]); - - ext_error_code = ACA_REG__STATUS__ERRORCODEEXT(status); - if (umc_v12_0_is_deferred_error(adev, status)) - count = ext_error_code == 0 ? - adev->umc.err_addr_cnt / adev->umc.retire_unit : 1ULL; - else - count = ext_error_code == 0 ? - ACA_REG__MISC0__ERRCNT(bank->regs[ACA_REG_IDX_MISC0]) : 1ULL; - - return aca_error_cache_log_bank_error(handle, &info, err_type, count); -} - -static const struct aca_bank_ops umc_v12_0_aca_bank_ops = { - .aca_bank_parser = umc_v12_0_aca_bank_parser, -}; - -const struct aca_info umc_v12_0_aca_info = { - .hwip = ACA_HWIP_TYPE_UMC, - .mask = ACA_ERROR_UE_MASK | ACA_ERROR_CE_MASK | ACA_ERROR_DEFERRED_MASK, - .bank_ops = &umc_v12_0_aca_bank_ops, -}; - -static int umc_v12_0_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) -{ - int ret; - - ret = amdgpu_umc_ras_late_init(adev, ras_block); - if (ret) - return ret; - - ret = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__UMC, - &umc_v12_0_aca_info, NULL); - if (ret) - return ret; - - return 0; -} - -static int umc_v12_0_update_ecc_status(struct amdgpu_device *adev, - uint64_t status, uint64_t ipid, uint64_t addr) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - uint16_t hwid, mcatype; - uint64_t page_pfn[UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL]; - uint64_t err_addr, pa_addr = 0; - struct ras_ecc_err *ecc_err; - struct ta_ras_query_address_output addr_out; - uint32_t shift_bit = adev->umc.flip_bits.flip_bits_in_pa[2]; - int count, ret, i; - - hwid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, HardwareID); - mcatype = REG_GET_FIELD(ipid, MCMP1_IPIDT0, McaType); - - /* The IP block decode of consumption is SMU */ - if (hwid != MCA_UMC_HWID_V12_0 || mcatype != MCA_UMC_MCATYPE_V12_0) { - con->umc_ecc_log.consumption_q_count++; - return 0; - } - - if (!status) - return 0; - - if (!umc_v12_0_is_deferred_error(adev, status)) - return 0; - - err_addr = REG_GET_FIELD(addr, - MCA_UMC_UMC0_MCUMC_ADDRT0, ErrorAddr); - - dev_dbg(adev->dev, - "UMC:IPID:0x%llx, socket:%llu, aid:%llu, inst:%llu, ch:%llu, err_addr:0x%llx\n", - ipid, - MCA_IPID_2_SOCKET_ID(ipid), - MCA_IPID_2_DIE_ID(ipid), - MCA_IPID_2_UMC_INST(ipid), - MCA_IPID_2_UMC_CH(ipid), - err_addr); - - ret = amdgpu_umc_mca_to_addr(adev, - err_addr, MCA_IPID_2_UMC_CH(ipid), - MCA_IPID_2_UMC_INST(ipid), MCA_IPID_2_DIE_ID(ipid), - MCA_IPID_2_SOCKET_ID(ipid), &addr_out, true); - if (ret) - return ret; - - ecc_err = kzalloc_obj(*ecc_err); - if (!ecc_err) - return -ENOMEM; - - pa_addr = addr_out.pa.pa; - ecc_err->status = status; - ecc_err->ipid = ipid; - ecc_err->addr = addr; - ecc_err->pa_pfn = pa_addr >> AMDGPU_GPU_PAGE_SHIFT; - ecc_err->channel_idx = addr_out.pa.channel_idx; - - /* If converted pa_pfn is 0, use pa C4 pfn. */ - if (!ecc_err->pa_pfn) - ecc_err->pa_pfn = BIT_ULL(shift_bit) >> AMDGPU_GPU_PAGE_SHIFT; - - ret = amdgpu_umc_logs_ecc_err(adev, &con->umc_ecc_log.de_page_tree, ecc_err); - if (ret) { - if (ret == -EEXIST) - con->umc_ecc_log.de_queried_count++; - else - dev_err(adev->dev, "Fail to log ecc error! ret:%d\n", ret); - - kfree(ecc_err); - return ret; - } - - con->umc_ecc_log.de_queried_count++; - - memset(page_pfn, 0, sizeof(page_pfn)); - count = amdgpu_umc_lookup_bad_pages_in_a_row(adev, - pa_addr, - page_pfn, ARRAY_SIZE(page_pfn)); - if (count <= 0) { - dev_warn(adev->dev, "Fail to convert error address! count:%d\n", count); - return 0; - } - - /* Reserve memory */ - for (i = 0; i < count; i++) - amdgpu_ras_reserve_page(adev, page_pfn[i]); - - /* The problem case is as follows: - * 1. GPU A triggers a gpu ras reset, and GPU A drives - * GPU B to also perform a gpu ras reset. - * 2. After gpu B ras reset started, gpu B queried a DE - * data. Since the DE data was queried in the ras reset - * thread instead of the page retirement thread, bad - * page retirement work would not be triggered. Then - * even if all gpu resets are completed, the bad pages - * will be cached in RAM until GPU B's bad page retirement - * work is triggered again and then saved to eeprom. - * Trigger delayed work to save the bad pages to eeprom in time - * after gpu ras reset is completed. - */ - if (amdgpu_ras_in_recovery(adev)) - schedule_delayed_work(&con->page_retirement_dwork, - msecs_to_jiffies(DELAYED_TIME_FOR_GPU_RESET)); - - return 0; -} - -static int umc_v12_0_fill_error_record(struct amdgpu_device *adev, - struct ras_ecc_err *ecc_err, void *ras_error_status) -{ - struct ras_err_data *err_data = (struct ras_err_data *)ras_error_status; - uint64_t page_pfn[UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL]; - int ret, i, count; - - if (!err_data || !ecc_err) - return -EINVAL; - - memset(page_pfn, 0, sizeof(page_pfn)); - count = amdgpu_umc_lookup_bad_pages_in_a_row(adev, - ecc_err->pa_pfn << AMDGPU_GPU_PAGE_SHIFT, - page_pfn, ARRAY_SIZE(page_pfn)); - - for (i = 0; i < count; i++) { - ret = amdgpu_umc_fill_error_record(err_data, - ecc_err->addr, - page_pfn[i] << AMDGPU_GPU_PAGE_SHIFT, - ecc_err->channel_idx, - MCA_IPID_2_UMC_INST(ecc_err->ipid)); - if (ret) - break; - } - - err_data->de_count++; - - return ret; -} - -static void umc_v12_0_query_ras_ecc_err_addr(struct amdgpu_device *adev, - void *ras_error_status) -{ - struct amdgpu_ras *con = amdgpu_ras_get_context(adev); - struct ras_ecc_err *entries[MAX_ECC_NUM_PER_RETIREMENT]; - struct radix_tree_root *ecc_tree; - int new_detected, ret, i; - - ecc_tree = &con->umc_ecc_log.de_page_tree; - - mutex_lock(&con->umc_ecc_log.lock); - new_detected = radix_tree_gang_lookup_tag(ecc_tree, (void **)entries, - 0, ARRAY_SIZE(entries), UMC_ECC_NEW_DETECTED_TAG); - for (i = 0; i < new_detected; i++) { - if (!entries[i]) - continue; - - ret = umc_v12_0_fill_error_record(adev, entries[i], ras_error_status); - if (ret) { - dev_err(adev->dev, "Fail to fill umc error record, ret:%d\n", ret); - break; - } - radix_tree_tag_clear(ecc_tree, - entries[i]->pa_pfn, UMC_ECC_NEW_DETECTED_TAG); - } - mutex_unlock(&con->umc_ecc_log.lock); -} - -static uint32_t umc_v12_0_get_die_id(struct amdgpu_device *adev, - uint64_t mca_addr, uint64_t retired_page) -{ - uint32_t die = 0; - - /* we only calculate die id for nps1 mode right now */ - die += ((((retired_page >> 12) & 0x1ULL)^ - ((retired_page >> 20) & 0x1ULL) ^ - ((retired_page >> 27) & 0x1ULL) ^ - ((retired_page >> 34) & 0x1ULL) ^ - ((retired_page >> 41) & 0x1ULL)) << 0); - - /* the original PA_C4 and PA_R13 may be cleared in retired_page, so - * get them from mca_addr. - */ - die += ((((retired_page >> 13) & 0x1ULL) ^ - ((mca_addr >> 5) & 0x1ULL) ^ - ((retired_page >> 28) & 0x1ULL) ^ - ((mca_addr >> 23) & 0x1ULL) ^ - ((retired_page >> 42) & 0x1ULL)) << 1); - die &= 3; - - return die; -} - -static void umc_v12_0_mca_ipid_parse(struct amdgpu_device *adev, uint64_t ipid, - uint32_t *did, uint32_t *ch, uint32_t *umc_inst, uint32_t *sid) -{ - if (did) - *did = MCA_IPID_2_DIE_ID(ipid); - if (ch) - *ch = MCA_IPID_2_UMC_CH(ipid); - if (umc_inst) - *umc_inst = MCA_IPID_2_UMC_INST(ipid); - if (sid) - *sid = MCA_IPID_2_SOCKET_ID(ipid); -} - struct amdgpu_umc_ras umc_v12_0_ras = { .ras_block = { - .hw_ops = &umc_v12_0_ras_hw_ops, - .ras_late_init = umc_v12_0_ras_late_init, + .hw_ops = NULL, }, - .err_cnt_init = umc_v12_0_err_cnt_init, - .query_ras_poison_mode = umc_v12_0_query_ras_poison_mode, - .ecc_info_query_ras_error_address = umc_v12_0_query_ras_ecc_err_addr, .check_ecc_err_status = umc_v12_0_check_ecc_err_status, - .update_ecc_status = umc_v12_0_update_ecc_status, - .convert_ras_err_addr = umc_v12_0_convert_error_address, - .get_die_id_from_pa = umc_v12_0_get_die_id, .get_retire_flip_bits = umc_v12_0_get_retire_flip_bits, - .mca_ipid_parse = umc_v12_0_mca_ipid_parse, }; diff --git a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h index 63b7e7254526..9d9e84d8d3bb 100644 --- a/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h +++ b/drivers/gpu/drm/amd/amdgpu/umc_v12_0.h @@ -26,31 +26,6 @@ #include "soc15_common.h" #include "amdgpu.h" -#define UMC_V12_0_NODE_DIST 0x40000000 -#define UMC_V12_0_INST_DIST 0x40000 - -/* UMC register per channel offset */ -#define UMC_V12_0_PER_CHANNEL_OFFSET 0x400 - -/* UMC cross node offset */ -#define UMC_V12_0_CROSS_NODE_OFFSET 0x100000000 - -/* OdEccErrCnt max value */ -#define UMC_V12_0_CE_CNT_MAX 0xffff -/* umc ce interrupt threshold */ -#define UMC_V12_0_CE_INT_THRESHOLD 0xffff -/* umc ce count initial value */ -#define UMC_V12_0_CE_CNT_INIT (UMC_V12_0_CE_CNT_MAX - UMC_V12_0_CE_INT_THRESHOLD) - -/* number of umc channel instance with memory map register access */ -#define UMC_V12_0_CHANNEL_INSTANCE_NUM 8 -/* number of umc instance with memory map register access */ -#define UMC_V12_0_UMC_INSTANCE_NUM 4 - -/* Total channel instances for all available umc nodes */ -#define UMC_V12_0_TOTAL_CHANNEL_NUM(adev) \ - (UMC_V12_0_CHANNEL_INSTANCE_NUM * (adev)->gmc.num_umc) - /* one piece of normalized address is mapped to 8 pieces of physical address */ #define UMC_V12_0_NA_MAP_PA_NUM 8 /* R13 bit shift should be considered, double the number */ @@ -75,9 +50,6 @@ /* row bits in MCA address */ #define UMC_V12_0_MA_R0_BIT 10 -#define MCA_UMC_HWID_V12_0 0x96 -#define MCA_UMC_MCATYPE_V12_0 0x0 - #define MCA_IPID_LO_2_UMC_CH(_ipid_lo) (((((_ipid_lo) >> 20) & 0x1) * 4) + \ (((_ipid_lo) >> 12) & 0xF)) #define MCA_IPID_LO_2_UMC_INST(_ipid_lo) (((_ipid_lo) >> 21) & 0x7) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index ecd7ead7a60b..8bb9592b0981 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -1165,36 +1165,6 @@ static int uvd_v6_0_wait_for_idle(struct amdgpu_ip_block *ip_block) } #define AMDGPU_UVD_STATUS_BUSY_MASK 0xfd -static bool uvd_v6_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 srbm_soft_reset = 0; - u32 tmp = RREG32(mmSRBM_STATUS); - - if (REG_GET_FIELD(tmp, SRBM_STATUS, UVD_RQ_PENDING) || - REG_GET_FIELD(tmp, SRBM_STATUS, UVD_BUSY) || - (RREG32(mmUVD_STATUS) & AMDGPU_UVD_STATUS_BUSY_MASK)) - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_UVD, 1); - - if (srbm_soft_reset) { - adev->uvd.inst->srbm_soft_reset = srbm_soft_reset; - return true; - } else { - adev->uvd.inst->srbm_soft_reset = 0; - return false; - } -} - -static int uvd_v6_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - if (!adev->uvd.inst->srbm_soft_reset) - return 0; - - uvd_v6_0_stop(adev); - return 0; -} static int uvd_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) { @@ -1227,18 +1197,6 @@ static int uvd_v6_0_soft_reset(struct amdgpu_ip_block *ip_block) return 0; } -static int uvd_v6_0_post_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - if (!adev->uvd.inst->srbm_soft_reset) - return 0; - - mdelay(5); - - return uvd_v6_0_start(adev); -} - static int uvd_v6_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, @@ -1538,10 +1496,7 @@ static const struct amd_ip_funcs uvd_v6_0_ip_funcs = { .resume = uvd_v6_0_resume, .is_idle = uvd_v6_0_is_idle, .wait_for_idle = uvd_v6_0_wait_for_idle, - .check_soft_reset = uvd_v6_0_check_soft_reset, - .pre_soft_reset = uvd_v6_0_pre_soft_reset, .soft_reset = uvd_v6_0_soft_reset, - .post_soft_reset = uvd_v6_0_post_soft_reset, .set_clockgating_state = uvd_v6_0_set_clockgating_state, .set_powergating_state = uvd_v6_0_set_powergating_state, .get_clockgating_state = uvd_v6_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index c69f7d82060f..9f4e88440c0a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -631,47 +631,6 @@ static int vce_v3_0_wait_for_idle(struct amdgpu_ip_block *ip_block) #define AMDGPU_VCE_STATUS_BUSY_MASK (VCE_STATUS_VCPU_REPORT_AUTO_BUSY_MASK | \ VCE_STATUS_VCPU_REPORT_RB0_BUSY_MASK) -static bool vce_v3_0_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - u32 srbm_soft_reset = 0; - - /* According to VCE team , we should use VCE_STATUS instead - * SRBM_STATUS.VCE_BUSY bit for busy status checking. - * GRBM_GFX_INDEX.INSTANCE_INDEX is used to specify which VCE - * instance's registers are accessed - * (0 for 1st instance, 10 for 2nd instance). - * - *VCE_STATUS - *|UENC|ACPI|AUTO ACTIVE|RB1 |RB0 |RB2 | |FW_LOADED|JOB | - *|----+----+-----------+----+----+----+----------+---------+----| - *|bit8|bit7| bit6 |bit5|bit4|bit3| bit2 | bit1 |bit0| - * - * VCE team suggest use bit 3--bit 6 for busy status check - */ - mutex_lock(&adev->grbm_idx_mutex); - WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); - if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); - } - WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); - if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); - srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); - } - WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); - mutex_unlock(&adev->grbm_idx_mutex); - - if (srbm_soft_reset) { - adev->vce.srbm_soft_reset = srbm_soft_reset; - return true; - } else { - adev->vce.srbm_soft_reset = 0; - return false; - } -} - static int vce_v3_0_soft_reset(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -703,31 +662,6 @@ static int vce_v3_0_soft_reset(struct amdgpu_ip_block *ip_block) return 0; } -static int vce_v3_0_pre_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - if (!adev->vce.srbm_soft_reset) - return 0; - - mdelay(5); - - return vce_v3_0_suspend(ip_block); -} - - -static int vce_v3_0_post_soft_reset(struct amdgpu_ip_block *ip_block) -{ - struct amdgpu_device *adev = ip_block->adev; - - if (!adev->vce.srbm_soft_reset) - return 0; - - mdelay(5); - - return vce_v3_0_resume(ip_block); -} - static int vce_v3_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, unsigned type, @@ -909,10 +843,7 @@ static const struct amd_ip_funcs vce_v3_0_ip_funcs = { .resume = vce_v3_0_resume, .is_idle = vce_v3_0_is_idle, .wait_for_idle = vce_v3_0_wait_for_idle, - .check_soft_reset = vce_v3_0_check_soft_reset, - .pre_soft_reset = vce_v3_0_pre_soft_reset, .soft_reset = vce_v3_0_soft_reset, - .post_soft_reset = vce_v3_0_post_soft_reset, .set_clockgating_state = vce_v3_0_set_clockgating_state, .set_powergating_state = vce_v3_0_set_powergating_state, .get_clockgating_state = vce_v3_0_get_clockgating_state, diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c index 8b8184fe6764..0d8a3cea63ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c @@ -159,9 +159,8 @@ static void vcn_v2_5_ring_begin_use(struct amdgpu_ring *ring) struct amdgpu_device *adev = ring->adev; struct amdgpu_vcn_inst *v = &adev->vcn.inst[ring->me]; - atomic_inc(&adev->vcn.inst[0].total_submission_cnt); - - cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work); + if (!atomic_fetch_inc(&adev->vcn.inst[0].total_submission_cnt)) + cancel_delayed_work_sync(&adev->vcn.inst[0].idle_work); /* We can safely return early here because we've cancelled the * the delayed work so there is no one else to set it to false @@ -207,10 +206,9 @@ static void vcn_v2_5_ring_end_use(struct amdgpu_ring *ring) !adev->vcn.inst[ring->me].using_unified_queue) atomic_dec(&adev->vcn.inst[ring->me].dpg_enc_submission_cnt); - atomic_dec(&adev->vcn.inst[0].total_submission_cnt); - - schedule_delayed_work(&adev->vcn.inst[0].idle_work, - VCN_IDLE_TIMEOUT); + if (atomic_dec_and_test(&adev->vcn.inst[0].total_submission_cnt)) + schedule_delayed_work(&adev->vcn.inst[0].idle_work, + VCN_IDLE_TIMEOUT); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c index ff7269bafae8..0cce78b205a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c @@ -1927,14 +1927,17 @@ static int vcn_v4_0_dec_msg(struct amdgpu_cs_parser *p, struct amdgpu_job *job, #define RENCODE_IB_PARAM_SESSION_INIT 0x00000003 /* return the offset in ib if id is found, -1 otherwise */ -static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start) +static int vcn_v4_0_enc_find_ib_param(struct amdgpu_ib *ib, uint32_t id, int start, uint32_t *length) { int i; uint32_t len; for (i = start; (len = amdgpu_ib_get_value(ib, i)) >= 8; i += len / 4) { - if (amdgpu_ib_get_value(ib, i + 1) == id) + if (amdgpu_ib_get_value(ib, i + 1) == id) { + if (length) + *length = len; return i; + } } return -1; } @@ -1944,14 +1947,14 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, struct amdgpu_ib *ib) { struct amdgpu_ring *ring = amdgpu_job_ring(job); - uint32_t val; + uint32_t val, len; int idx = 0, sidx; /* The first instance can decode anything */ if (!ring->me) return 0; - while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx)) >= 0) { + while ((idx = vcn_v4_0_enc_find_ib_param(ib, RADEON_VCN_ENGINE_INFO, idx, &len)) >= 0) { val = amdgpu_ib_get_value(ib, idx + 2); /* RADEON_VCN_ENGINE_TYPE */ if (val == RADEON_VCN_ENGINE_TYPE_DECODE) { uint32_t valid_buf_flag = amdgpu_ib_get_value(ib, idx + 6); @@ -1964,12 +1967,12 @@ static int vcn_v4_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p, amdgpu_ib_get_value(ib, idx + 8); return vcn_v4_0_dec_msg(p, job, msg_buffer_addr); } else if (val == RADEON_VCN_ENGINE_TYPE_ENCODE) { - sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx); + sidx = vcn_v4_0_enc_find_ib_param(ib, RENCODE_IB_PARAM_SESSION_INIT, idx, NULL); if (sidx >= 0 && amdgpu_ib_get_value(ib, sidx + 2) == RENCODE_ENCODE_STANDARD_AV1) return vcn_v4_0_limit_sched(p, job); } - idx += amdgpu_ib_get_value(ib, idx) / 4; + idx += len / 4; } return 0; } @@ -1992,7 +1995,7 @@ static int vcn_v4_0_ring_reset(struct amdgpu_ring *ring, return amdgpu_ring_reset_helper_end(ring, timedout_fence); } -static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { +static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, @@ -2025,6 +2028,40 @@ static struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs = { .reset = vcn_v4_0_ring_reset, }; +static const struct amdgpu_ring_funcs vcn_v4_0_unified_ring_vm_funcs_secure = { + .type = AMDGPU_RING_TYPE_VCN_ENC, + .align_mask = 0x3f, + .nop = VCN_ENC_CMD_NO_OP, + .secure_submission_supported = true, + .no_user_fence = true, + .extra_bytes = sizeof(struct amdgpu_vcn_rb_metadata), + .get_rptr = vcn_v4_0_unified_ring_get_rptr, + .get_wptr = vcn_v4_0_unified_ring_get_wptr, + .set_wptr = vcn_v4_0_unified_ring_set_wptr, + .patch_cs_in_place = vcn_v4_0_ring_patch_cs_in_place, + .emit_frame_size = + SOC15_FLUSH_GPU_TLB_NUM_WREG * 3 + + SOC15_FLUSH_GPU_TLB_NUM_REG_WAIT * 4 + + 4 + /* vcn_v2_0_enc_ring_emit_vm_flush */ + 5 + 5 + /* vcn_v2_0_enc_ring_emit_fence x2 vm fence */ + 1, /* vcn_v2_0_enc_ring_insert_end */ + .emit_ib_size = 5, /* vcn_v2_0_enc_ring_emit_ib */ + .emit_ib = vcn_v2_0_enc_ring_emit_ib, + .emit_fence = vcn_v2_0_enc_ring_emit_fence, + .emit_vm_flush = vcn_v2_0_enc_ring_emit_vm_flush, + .test_ring = amdgpu_vcn_enc_ring_test_ring, + .test_ib = amdgpu_vcn_unified_ring_test_ib, + .insert_nop = amdgpu_ring_insert_nop, + .insert_end = vcn_v2_0_enc_ring_insert_end, + .pad_ib = amdgpu_ring_generic_pad_ib, + .begin_use = amdgpu_vcn_ring_begin_use, + .end_use = amdgpu_vcn_ring_end_use, + .emit_wreg = vcn_v2_0_enc_ring_emit_wreg, + .emit_reg_wait = vcn_v2_0_enc_ring_emit_reg_wait, + .emit_reg_write_reg_wait = amdgpu_ring_emit_reg_write_reg_wait_helper, + .reset = vcn_v4_0_ring_reset, +}; + /** * vcn_v4_0_set_unified_ring_funcs - set unified ring functions * @@ -2041,10 +2078,11 @@ static void vcn_v4_0_set_unified_ring_funcs(struct amdgpu_device *adev) continue; if (amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 2)) - vcn_v4_0_unified_ring_vm_funcs.secure_submission_supported = true; - - adev->vcn.inst[i].ring_enc[0].funcs = - (const struct amdgpu_ring_funcs *)&vcn_v4_0_unified_ring_vm_funcs; + adev->vcn.inst[i].ring_enc[0].funcs = + &vcn_v4_0_unified_ring_vm_funcs_secure; + else + adev->vcn.inst[i].ring_enc[0].funcs = + &vcn_v4_0_unified_ring_vm_funcs; adev->vcn.inst[i].ring_enc[0].me = i; } } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c index 7f001c32e911..179b892fb410 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c @@ -115,6 +115,19 @@ static int vcn_v4_0_3_early_init(struct amdgpu_ip_block *ip_block) struct amdgpu_device *adev = ip_block->adev; int i, r; + switch (amdgpu_user_queue) { + case -1: + case 0: + default: + adev->vcn.disable_kq = false; + adev->vcn.disable_uq = true; + break; + case 2: + adev->vcn.disable_kq = true; + adev->vcn.disable_uq = true; + break; + } + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) /* re-use enc ring as unified ring */ adev->vcn.inst[i].num_enc_rings = 1; @@ -217,6 +230,10 @@ static int vcn_v4_0_3_sw_init(struct amdgpu_ip_block *ip_block) ring = &adev->vcn.inst[i].ring_enc[0]; ring->use_doorbell = true; + if (adev->vcn.disable_kq) { + ring->no_scheduler = true; + ring->no_user_submission = true; + } if (!amdgpu_sriov_vf(adev)) ring->doorbell_index = @@ -2146,71 +2163,6 @@ static const struct amdgpu_ras_block_hw_ops vcn_v4_0_3_ras_hw_ops = { .query_poison_status = vcn_v4_0_3_query_poison_status, }; -static int vcn_v4_0_3_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct aca_bank_info info; - u64 misc0; - int ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - misc0 = bank->regs[ACA_REG_IDX_MISC0]; - switch (type) { - case ACA_SMU_TYPE_UE: - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, - 1ULL); - break; - case ACA_SMU_TYPE_CE: - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, - ACA_REG__MISC0__ERRCNT(misc0)); - break; - default: - return -EINVAL; - } - - return ret; -} - -/* reference to smu driver if header file */ -static int vcn_v4_0_3_err_codes[] = { - 14, 15, /* VCN */ -}; - -static bool vcn_v4_0_3_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - u32 instlo; - - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - - if (instlo != mmSMNAID_AID0_MCA_SMU) - return false; - - if (aca_bank_check_error_codes(handle->adev, bank, - vcn_v4_0_3_err_codes, - ARRAY_SIZE(vcn_v4_0_3_err_codes))) - return false; - - return true; -} - -static const struct aca_bank_ops vcn_v4_0_3_aca_bank_ops = { - .aca_bank_parser = vcn_v4_0_3_aca_bank_parser, - .aca_bank_is_valid = vcn_v4_0_3_aca_bank_is_valid, -}; - -static const struct aca_info vcn_v4_0_3_aca_info = { - .hwip = ACA_HWIP_TYPE_SMU, - .mask = ACA_ERROR_UE_MASK, - .bank_ops = &vcn_v4_0_3_aca_bank_ops, -}; - static int vcn_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) { int r; @@ -2226,11 +2178,6 @@ static int vcn_v4_0_3_ras_late_init(struct amdgpu_device *adev, struct ras_commo goto late_fini; } - r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__VCN, - &vcn_v4_0_3_aca_info, NULL); - if (r) - goto late_fini; - return 0; late_fini: diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c index 1571cc5a148c..c8879a6e5297 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c @@ -1479,10 +1479,11 @@ static int vcn_v4_0_5_ring_reset(struct amdgpu_ring *ring, return amdgpu_ring_reset_helper_end(ring, timedout_fence); } -static struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { +static const struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .secure_submission_supported = true, .no_user_fence = true, .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, @@ -1525,9 +1526,6 @@ static void vcn_v4_0_5_set_unified_ring_funcs(struct amdgpu_device *adev) if (adev->vcn.harvest_config & (1 << i)) continue; - if (amdgpu_ip_version(adev, VCN_HWIP, 0) == IP_VERSION(4, 0, 5)) - vcn_v4_0_5_unified_ring_vm_funcs.secure_submission_supported = true; - adev->vcn.inst[i].ring_enc[0].funcs = &vcn_v4_0_5_unified_ring_vm_funcs; adev->vcn.inst[i].ring_enc[0].me = i; } diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c index d3db0494341e..1a07c3bf4425 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_1.c @@ -94,6 +94,19 @@ static int vcn_v5_0_1_early_init(struct amdgpu_ip_block *ip_block) struct amdgpu_device *adev = ip_block->adev; int i, r; + switch (amdgpu_user_queue) { + case -1: + case 0: + default: + adev->vcn.disable_kq = false; + adev->vcn.disable_uq = true; + break; + case 2: + adev->vcn.disable_kq = true; + adev->vcn.disable_uq = true; + break; + } + for (i = 0; i < adev->vcn.num_vcn_inst; ++i) /* re-use enc ring as unified ring */ adev->vcn.inst[i].num_enc_rings = 1; @@ -188,6 +201,10 @@ static int vcn_v5_0_1_sw_init(struct amdgpu_ip_block *ip_block) ring = &adev->vcn.inst[i].ring_enc[0]; ring->use_doorbell = true; + if (adev->vcn.disable_kq) { + ring->no_scheduler = true; + ring->no_user_submission = true; + } if (!amdgpu_sriov_vf(adev)) ring->doorbell_index = (adev->doorbell_index.vcn.vcn_ring0_1 << 1) + @@ -1657,10 +1674,7 @@ static const struct amd_ip_funcs vcn_v5_0_1_ip_funcs = { .resume = vcn_v5_0_1_resume, .is_idle = vcn_v5_0_1_is_idle, .wait_for_idle = vcn_v5_0_1_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v5_0_1_set_clockgating_state, .set_powergating_state = vcn_set_powergating_state, .dump_ip_state = amdgpu_vcn_dump_ip_state, @@ -1713,71 +1727,6 @@ static const struct amdgpu_ras_block_hw_ops vcn_v5_0_1_ras_hw_ops = { .query_poison_status = vcn_v5_0_1_query_poison_status, }; -static int vcn_v5_0_1_aca_bank_parser(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - struct aca_bank_info info; - u64 misc0; - int ret; - - ret = aca_bank_info_decode(bank, &info); - if (ret) - return ret; - - misc0 = bank->regs[ACA_REG_IDX_MISC0]; - switch (type) { - case ACA_SMU_TYPE_UE: - bank->aca_err_type = ACA_ERROR_TYPE_UE; - ret = aca_error_cache_log_bank_error(handle, &info, ACA_ERROR_TYPE_UE, - 1ULL); - break; - case ACA_SMU_TYPE_CE: - bank->aca_err_type = ACA_ERROR_TYPE_CE; - ret = aca_error_cache_log_bank_error(handle, &info, bank->aca_err_type, - ACA_REG__MISC0__ERRCNT(misc0)); - break; - default: - return -EINVAL; - } - - return ret; -} - -/* reference to smu driver if header file */ -static int vcn_v5_0_1_err_codes[] = { - 14, 15, 47, /* VCN [D|V|S] */ -}; - -static bool vcn_v5_0_1_aca_bank_is_valid(struct aca_handle *handle, struct aca_bank *bank, - enum aca_smu_type type, void *data) -{ - u32 instlo; - - instlo = ACA_REG__IPID__INSTANCEIDLO(bank->regs[ACA_REG_IDX_IPID]); - instlo &= GENMASK(31, 1); - - if (instlo != mmSMNAID_AID0_MCA_SMU) - return false; - - if (aca_bank_check_error_codes(handle->adev, bank, - vcn_v5_0_1_err_codes, - ARRAY_SIZE(vcn_v5_0_1_err_codes))) - return false; - - return true; -} - -static const struct aca_bank_ops vcn_v5_0_1_aca_bank_ops = { - .aca_bank_parser = vcn_v5_0_1_aca_bank_parser, - .aca_bank_is_valid = vcn_v5_0_1_aca_bank_is_valid, -}; - -static const struct aca_info vcn_v5_0_1_aca_info = { - .hwip = ACA_HWIP_TYPE_SMU, - .mask = ACA_ERROR_UE_MASK, - .bank_ops = &vcn_v5_0_1_aca_bank_ops, -}; - static int vcn_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block) { int r; @@ -1786,11 +1735,6 @@ static int vcn_v5_0_1_ras_late_init(struct amdgpu_device *adev, struct ras_commo if (r) return r; - r = amdgpu_ras_bind_aca(adev, AMDGPU_RAS_BLOCK__VCN, - &vcn_v5_0_1_aca_info, NULL); - if (r) - goto late_fini; - if (amdgpu_ras_is_supported(adev, ras_block->block) && adev->vcn.inst->ras_poison_irq.funcs) { r = amdgpu_irq_get(adev, &adev->vcn.inst->ras_poison_irq, 0); diff --git a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c index bbc172db91a1..b9f6ae75ea72 100644 --- a/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c +++ b/drivers/gpu/drm/amd/amdgpu/vcn_v5_0_2.c @@ -1203,10 +1203,7 @@ static const struct amd_ip_funcs vcn_v5_0_2_ip_funcs = { .resume = vcn_v5_0_2_resume, .is_idle = vcn_v5_0_2_is_idle, .wait_for_idle = vcn_v5_0_2_wait_for_idle, - .check_soft_reset = NULL, - .pre_soft_reset = NULL, .soft_reset = NULL, - .post_soft_reset = NULL, .set_clockgating_state = vcn_v5_0_2_set_clockgating_state, .set_powergating_state = vcn_set_powergating_state, }; diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index a256320b92f3..5715b6b596af 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1328,27 +1328,6 @@ static void vi_invalidate_hdp(struct amdgpu_device *adev, } } -static bool vi_need_full_reset(struct amdgpu_device *adev) -{ - switch (adev->asic_type) { - case CHIP_CARRIZO: - case CHIP_STONEY: - /* CZ has hang issues with full reset at the moment */ - return false; - case CHIP_FIJI: - case CHIP_TONGA: - /* XXX: soft reset should work on fiji and tonga */ - return true; - case CHIP_POLARIS10: - case CHIP_POLARIS11: - case CHIP_POLARIS12: - case CHIP_TOPAZ: - default: - /* change this when we support soft reset */ - return true; - } -} - static void vi_get_pcie_usage(struct amdgpu_device *adev, uint64_t *count0, uint64_t *count1) { @@ -1437,7 +1416,6 @@ static const struct amdgpu_asic_funcs vi_asic_funcs = .get_config_memsize = &vi_get_config_memsize, .flush_hdp = &vi_flush_hdp, .invalidate_hdp = &vi_invalidate_hdp, - .need_full_reset = &vi_need_full_reset, .init_doorbell_index = &legacy_doorbell_index_init, .get_pcie_usage = &vi_get_pcie_usage, .need_reset_on_init = &vi_need_reset_on_init, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 531e20748198..411ee894f623 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -1783,9 +1783,6 @@ static int kfd_ptl_control(struct kfd_process_device *pdd, bool enable) uint32_t ptl_state = enable ? 1 : 0; int ret; - if (!ptl->hw_supported) - return -EOPNOTSUPP; - if (!pdd->dev->kfd2kgd || !pdd->dev->kfd2kgd->ptl_ctrl) return -EOPNOTSUPP; @@ -1804,6 +1801,9 @@ int kfd_ptl_disable_request(struct kfd_process_device *pdd, struct amdgpu_ptl *ptl = &adev->psp.ptl; int ret = 0; + if (!ptl->hw_supported) + return -EOPNOTSUPP; + mutex_lock(&ptl->mutex); if (pdd->ptl_disable_req) @@ -1833,6 +1833,9 @@ int kfd_ptl_disable_release(struct kfd_process_device *pdd, struct amdgpu_ptl *ptl = &adev->psp.ptl; int ret = 0; + if (!ptl->hw_supported) + return -EOPNOTSUPP; + mutex_lock(&ptl->mutex); if (!pdd->ptl_disable_req) @@ -1914,13 +1917,13 @@ static int criu_checkpoint_devices(struct kfd_process *p, struct kfd_criu_device_bucket *device_buckets = NULL; int ret = 0, i; - device_buckets = kvzalloc(num_devices * sizeof(*device_buckets), GFP_KERNEL); + device_buckets = kvcalloc(num_devices, sizeof(*device_buckets), GFP_KERNEL); if (!device_buckets) { ret = -ENOMEM; goto exit; } - device_priv = kvzalloc(num_devices * sizeof(*device_priv), GFP_KERNEL); + device_priv = kvcalloc(num_devices, sizeof(*device_priv), GFP_KERNEL); if (!device_priv) { ret = -ENOMEM; goto exit; @@ -2040,17 +2043,17 @@ static int criu_checkpoint_bos(struct kfd_process *p, int ret = 0, pdd_index, bo_index = 0, id; void *mem; - bo_buckets = kvzalloc(num_bos * sizeof(*bo_buckets), GFP_KERNEL); + bo_buckets = kvcalloc(num_bos, sizeof(*bo_buckets), GFP_KERNEL); if (!bo_buckets) return -ENOMEM; - bo_privs = kvzalloc(num_bos * sizeof(*bo_privs), GFP_KERNEL); + bo_privs = kvcalloc(num_bos, sizeof(*bo_privs), GFP_KERNEL); if (!bo_privs) { ret = -ENOMEM; goto exit; } - files = kvzalloc(num_bos * sizeof(struct file *), GFP_KERNEL); + files = kvcalloc(num_bos, sizeof(struct file *), GFP_KERNEL); if (!files) { ret = -ENOMEM; goto exit; @@ -2581,7 +2584,7 @@ static int criu_restore_bos(struct kfd_process *p, if (!bo_buckets) return -ENOMEM; - files = kvzalloc(args->num_bos * sizeof(struct file *), GFP_KERNEL); + files = kvcalloc(args->num_bos, sizeof(struct file *), GFP_KERNEL); if (!files) { ret = -ENOMEM; goto exit; @@ -3734,7 +3737,8 @@ static int kfd_mmap(struct file *filep, struct vm_area_struct *vma) return kfd_doorbell_mmap(dev, process, vma); case KFD_MMAP_TYPE_EVENTS: - return kfd_event_mmap(process, vma); + pr_warn("KFD_MMAP_TYPE_EVENTS is no longer supported\n"); + return -EINVAL; case KFD_MMAP_TYPE_RESERVED_MEM: pr_warn("KFD_MMAP_TYPE_RESERVED_MEM is no longer supported\n"); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index f28259d13818..2a239f45fc24 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -1715,6 +1715,8 @@ int kfd_get_gpu_cache_info(struct kfd_node *kdev, struct kfd_gpu_cache_info **pc case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): /* Cacheline size not available in IP discovery for gc11. * kfd_fill_gpu_cache_info_from_gfx_config to hard code it */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 5eb863dec8f4..586e640f13dc 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -169,6 +169,8 @@ static void kfd_device_info_set_event_interrupt_class(struct kfd_dev *kfd) case IP_VERSION(11, 5, 3): case IP_VERSION(11, 5, 4): case IP_VERSION(11, 5, 6): + case IP_VERSION(11, 7, 0): + case IP_VERSION(11, 7, 1): kfd->device_info.event_interrupt_class = &event_interrupt_class_v11; break; case IP_VERSION(12, 0, 0): @@ -451,6 +453,14 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf) gfx_target_version = 110504; f2g = &gfx_v11_kfd2kgd; break; + case IP_VERSION(11, 7, 0): + gfx_target_version = 110700; + f2g = &gfx_v11_kfd2kgd; + break; + case IP_VERSION(11, 7, 1): + gfx_target_version = 110701; + f2g = &gfx_v11_kfd2kgd; + break; case IP_VERSION(12, 0, 0): gfx_target_version = 120000; f2g = &gfx_v12_kfd2kgd; @@ -1796,6 +1806,30 @@ void kgd2kfd_teardown_processes(struct amdgpu_device *adev) cond_resched(); } +int kgd2kfd_reset_mes_queue(struct kfd_dev *kfd, uint32_t node_id, + int queue_type, int pipe, int queue, + unsigned int db) +{ + struct kfd_node *node; + int ret; + + if (!kfd->init_complete) + return 0; + + if (node_id >= kfd->num_nodes) { + dev_warn(kfd->adev->dev, "Invalid node ID: %u exceeds %u\n", + node_id, kfd->num_nodes - 1); + return -EINVAL; + } + node = kfd->nodes[node_id]; + + ret = kfd_reset_queue_mes(node->dqm, queue_type, pipe, queue, db); + if (ret) + dev_err(kfd_device, "Error resetting queue\n"); + + return ret; +} + #if defined(CONFIG_DEBUG_FS) /* This function will send a package to HIQ to hang the HWS diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index 2e010c1f8828..97402e6c8f83 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -37,7 +37,8 @@ #include "amdgpu_amdkfd.h" #include "amdgpu_reset.h" #include "amdgpu_sdma.h" -#include "mes_v11_api_def.h" +#include "amdgpu_ring.h" +#include "amdgpu_mes.h" #include "kfd_debug.h" /* Size of the per-pipe EOP queue */ @@ -71,12 +72,11 @@ static int allocate_sdma_queue(struct device_queue_manager *dqm, struct queue *q, const uint32_t *restore_sdma_id); static int reset_queues_on_hws_hang(struct device_queue_manager *dqm, bool is_sdma); -static int resume_all_queues_mes(struct device_queue_manager *dqm); -static int suspend_all_queues_mes(struct device_queue_manager *dqm); static struct queue *find_queue_by_doorbell_offset(struct device_queue_manager *dqm, u32 doorbell_offset); static void set_queue_as_reset(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd); +static int reset_queues_mes(struct device_queue_manager *dqm, struct queue *q); static inline enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type) @@ -184,24 +184,24 @@ static void kfd_hws_hang(struct device_queue_manager *dqm) amdgpu_amdkfd_gpu_reset(dqm->dev->adev); } -static int convert_to_mes_queue_type(int queue_type) +static int convert_to_amdgpu_ring_type(int queue_type) { - int mes_queue_type; + int amdgpu_ring_type; switch (queue_type) { case KFD_QUEUE_TYPE_COMPUTE: - mes_queue_type = MES_QUEUE_TYPE_COMPUTE; + amdgpu_ring_type = AMDGPU_RING_TYPE_COMPUTE; break; case KFD_QUEUE_TYPE_SDMA: - mes_queue_type = MES_QUEUE_TYPE_SDMA; + amdgpu_ring_type = AMDGPU_RING_TYPE_SDMA; break; default: WARN(1, "Invalid queue type %d", queue_type); - mes_queue_type = -EINVAL; + amdgpu_ring_type = -EINVAL; break; } - return mes_queue_type; + return amdgpu_ring_type; } static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, @@ -251,7 +251,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, (qpd->pqm->process->debug_trap_enabled || kfd_dbg_has_ttmps_always_setup(q->device)); - queue_type = convert_to_mes_queue_type(q->properties.type); + queue_type = convert_to_amdgpu_ring_type(q->properties.type); if (queue_type < 0) { dev_err(adev->dev, "Queue type not supported with MES, queue:%d\n", q->properties.type); @@ -300,6 +300,7 @@ static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, st memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input)); queue_input.doorbell_offset = q->properties.doorbell_off; queue_input.gang_context_addr = q->gang_ctx_gpu_addr; + queue_input.queue_type = convert_to_amdgpu_ring_type(q->properties.type); queue_input.remove_queue_after_reset = flush_mes_queue; queue_input.xcc_id = ffs(dqm->dev->xcc_mask) - 1; @@ -308,14 +309,14 @@ static int remove_queue_mes_on_reset_option(struct device_queue_manager *dqm, st amdgpu_mes_unlock(&adev->mes); up_read(&adev->reset_domain->sem); - if (is_for_reset) + /* If is_for_reset set, it is a mes internal cleanup */ + if (!r || is_for_reset) return r; - if (r) { - if (!suspend_all_queues_mes(dqm)) - return resume_all_queues_mes(dqm); - - dev_err(adev->dev, "failed to remove hardware queue from MES, doorbell=0x%x\n", + /* remove_hw_queue failure indicates a queue hang. reset the queue */ + r = reset_queues_mes(dqm, q); + if (r && amdgpu_gpu_recovery) { + dev_err(adev->dev, "failed to remove queue from MES, doorbell=0x%x\n", q->properties.doorbell_off); dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n"); kfd_hws_hang(dqm); @@ -407,16 +408,50 @@ static int add_all_kfd_queues_mes(struct device_queue_manager *dqm) return retval; } -static int reset_queues_mes(struct device_queue_manager *dqm) +static int reset_queue_mes(struct device_queue_manager *dqm, struct queue *q, + int queue_type, int pipe, int queue, unsigned int db) { struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; - int hqd_info_size = adev->mes.hung_queue_hqd_info_offset; - int num_hung = 0, r = 0, i, pipe, queue, queue_type; - u32 *hung_array = dqm->hung_db_array; - struct amdgpu_mes_hung_queue_hqd_info *hqd_info = dqm->hqd_info; struct kfd_process_device *pdd; + bool use_mmio = adev->gfx.mec.use_mmio_for_reset; + int r; + + pdd = kfd_get_process_device_data(q->device, q->process); + if (!pdd) + return -ENODEV; + + if (use_mmio) + r = amdgpu_mes_reset_queue_mmio(adev, queue_type, 0, 1, pipe, queue, + ffs(dqm->dev->xcc_mask) - 1); + else + r = amdgpu_mes_reset_user_queue(adev, queue_type, db, + ffs(dqm->dev->xcc_mask) - 1); + if (r) + return r; + /* Proceed remove_queue with reset=true */ + remove_queue_mes_on_reset_option(dqm, q, &pdd->qpd, true, true); + set_queue_as_reset(dqm, q, &pdd->qpd); + return 0; +} + +int kfd_reset_queue_mes(struct device_queue_manager *dqm, int queue_type, + int pipe, int queue, unsigned int db) +{ struct queue *q; + q = find_queue_by_doorbell_offset(dqm, db); + if (!q) + return 0; + return reset_queue_mes(dqm, q, queue_type, pipe, queue, db); +} + +static int reset_queues_mes(struct device_queue_manager *dqm, struct queue *q) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; + unsigned int num_hung = 0; + int r = 0; + struct mes_remove_queue_input queue_input; + if (!amdgpu_mes_queue_reset_by_mes_supported(adev)) { r = -ENOTRECOVERABLE; goto fail; @@ -431,111 +466,29 @@ static int reset_queues_mes(struct device_queue_manager *dqm) goto fail; } - if (!hung_array || !hqd_info) { - r = -ENOMEM; + memset(&queue_input, 0x0, sizeof(struct mes_remove_queue_input)); + queue_input.doorbell_offset = q->properties.doorbell_off; + queue_input.gang_context_addr = q->gang_ctx_gpu_addr; + queue_input.queue_type = convert_to_amdgpu_ring_type(q->properties.type); + queue_input.remove_queue_after_reset = false; + queue_input.xcc_id = ffs(dqm->dev->xcc_mask) - 1; + /* pass the known bad queue info to the reset function */ + r = amdgpu_gfx_reset_mes_compute(adev, NULL, NULL, NULL, &num_hung, &queue_input); + if (r) goto fail; - } - - memset(hqd_info, 0, hqd_info_size * sizeof(struct amdgpu_mes_hung_queue_hqd_info)); - - /* - * AMDGPU_RING_TYPE_COMPUTE parameter does not matter if called - * post suspend_all as reset & detect will return all hung queue types. - * - * Passed parameter is for targeting queues not scheduled by MES add_queue. - */ - r = amdgpu_mes_detect_and_reset_hung_queues(adev, AMDGPU_RING_TYPE_COMPUTE, - false, &num_hung, hung_array, ffs(dqm->dev->xcc_mask) - 1); - - if (!num_hung || r) { - r = -ENOTRECOVERABLE; - goto fail; - } - - /* MES resets queue/pipe and cleans up internally */ - for (i = 0; i < num_hung; i++) { - hqd_info[i].bit0_31 = hung_array[i + hqd_info_size]; - pipe = hqd_info[i].pipe_index; - queue = hqd_info[i].queue_index; - queue_type = hqd_info[i].queue_type; - - if (queue_type != MES_QUEUE_TYPE_COMPUTE && - queue_type != MES_QUEUE_TYPE_SDMA) { - pr_warn("Unsupported hung queue reset type: %d\n", queue_type); - hung_array[i] = AMDGPU_MES_INVALID_DB_OFFSET; - continue; - } - - q = find_queue_by_doorbell_offset(dqm, hung_array[i]); - if (!q) { - r = -ENOTRECOVERABLE; - goto fail; - } - - pdd = kfd_get_process_device_data(q->device, q->process); - if (!pdd) { - r = -ENODEV; - goto fail; - } - - pr_warn("Hang detected doorbell %x pipe %d queue %d type %d\n", - hung_array[i], pipe, queue, queue_type); - /* Proceed remove_queue with reset=true */ - remove_queue_mes_on_reset_option(dqm, q, &pdd->qpd, true, false); - set_queue_as_reset(dqm, q, &pdd->qpd); - } dqm->detect_hang_count = num_hung; - kfd_signal_reset_event(dqm->dev); + /* When MES doesn't detect any queue hang, no reset happens. Don't signal reset + * event. + */ + if (dqm->detect_hang_count) + kfd_signal_reset_event(dqm->dev); fail: dqm->detect_hang_count = 0; return r; } -static int suspend_all_queues_mes(struct device_queue_manager *dqm) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; - int r = 0; - - if (!down_read_trylock(&adev->reset_domain->sem)) - return -EIO; - - r = amdgpu_mes_suspend(adev, ffs(dqm->dev->xcc_mask) - 1); - up_read(&adev->reset_domain->sem); - - if (r) { - if (!reset_queues_mes(dqm)) - return 0; - - dev_err(adev->dev, "failed to suspend gangs from MES\n"); - dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n"); - kfd_hws_hang(dqm); - } - - return r; -} - -static int resume_all_queues_mes(struct device_queue_manager *dqm) -{ - struct amdgpu_device *adev = (struct amdgpu_device *)dqm->dev->adev; - int r = 0; - - if (!down_read_trylock(&adev->reset_domain->sem)) - return -EIO; - - r = amdgpu_mes_resume(adev, ffs(dqm->dev->xcc_mask) - 1); - up_read(&adev->reset_domain->sem); - - if (r) { - dev_err(adev->dev, "failed to resume gangs from MES\n"); - dev_err(adev->dev, "MES might be in unrecoverable state, issue a GPU reset\n"); - kfd_hws_hang(dqm); - } - - return r; -} - static void increment_queue_count(struct device_queue_manager *dqm, struct qcm_process_device *qpd, struct queue *q) @@ -1064,8 +1017,15 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm, /* Get the SDMA queue stats */ if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) || (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) { - retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr, - &sdma_val); + if (dqm->dev->kfd2kgd->hqd_sdma_get_counter) + retval = dqm->dev->kfd2kgd->hqd_sdma_get_counter( + dqm->dev->adev, q->mqd, + dqm->dev->kfd->device_info.num_sdma_queues_per_engine, + &sdma_val); + else + retval = read_sdma_queue_counter( + (uint64_t __user *)q->properties.read_ptr, + &sdma_val); if (retval) dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n", q->properties.queue_id); @@ -2703,8 +2663,16 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm, /* Get the SDMA queue stats */ if ((q->properties.type == KFD_QUEUE_TYPE_SDMA) || (q->properties.type == KFD_QUEUE_TYPE_SDMA_XGMI)) { - retval = read_sdma_queue_counter((uint64_t __user *)q->properties.read_ptr, - &sdma_val); + if (dqm->dev->kfd2kgd->hqd_sdma_get_counter) + retval = dqm->dev->kfd2kgd->hqd_sdma_get_counter( + dqm->dev->adev, q->mqd, + dqm->dev->kfd->device_info.num_sdma_queues_per_engine, + &sdma_val); + else + retval = read_sdma_queue_counter( + (uint64_t __user *)q->properties.read_ptr, + &sdma_val); + if (retval) dev_err(dev, "Failed to read SDMA queue counter for queue: %d\n", q->properties.queue_id); @@ -3244,12 +3212,12 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm) kfree(dqm); } +/* bad queue notified by interrupt from CP */ int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbell_id) { struct kfd_process_device *pdd = NULL; struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, &pdd); struct device_queue_manager *dqm = knode->dqm; - struct device *dev = dqm->dev->adev->dev; struct qcm_process_device *qpd; struct queue *q = NULL; int ret = 0; @@ -3264,19 +3232,10 @@ int kfd_dqm_suspend_bad_queue_mes(struct kfd_node *knode, u32 pasid, u32 doorbel list_for_each_entry(q, &qpd->queues_list, list) { if (q->doorbell_id == doorbell_id && q->properties.is_active) { - /* suspend all queues will save any good queues and mark the rest as bad */ - suspend_all_queues_mes(dqm); - + reset_queues_mes(dqm, q); q->properties.is_evicted = true; q->properties.is_active = false; decrement_queue_count(dqm, qpd, q); - - /* this will remove the bad queue and sched a GPU reset if needed */ - ret = remove_queue_mes(dqm, q, qpd); - if (ret) - dev_err(dev, "Removing bad queue failed"); - /* resume the good queues */ - resume_all_queues_mes(dqm); break; } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h index e0b6a47e7722..2229f8b2f446 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h @@ -333,6 +333,8 @@ int debug_refresh_runlist(struct device_queue_manager *dqm); bool kfd_dqm_is_queue_in_process(struct device_queue_manager *dqm, struct qcm_process_device *qpd, int doorbell_off, u32 *queue_format); +int kfd_reset_queue_mes(struct device_queue_manager *dqm, int queue_type, + int pipe, int queue, unsigned int db); static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_events.c index 81900b49d9d5..dae01e2bb464 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.c @@ -29,10 +29,12 @@ #include #include #include +#include #include "kfd_priv.h" #include "kfd_events.h" #include "kfd_device_queue_manager.h" #include +#include /* * Wrapper around wait_queue_entry_t @@ -44,67 +46,19 @@ struct kfd_event_waiter { bool event_age_enabled; /* set to true when last_event_age is non-zero */ }; -/* - * Each signal event needs a 64-bit signal slot where the signaler will write - * a 1 before sending an interrupt. (This is needed because some interrupts - * do not contain enough spare data bits to identify an event.) - * We get whole pages and map them to the process VA. - * Individual signal events use their event_id as slot index. - */ -struct kfd_signal_page { - uint64_t *kernel_address; - uint64_t __user *user_address; - bool need_to_free_pages; -}; - -static uint64_t *page_slots(struct kfd_signal_page *page) -{ - return page->kernel_address; -} - -static struct kfd_signal_page *allocate_signal_page(struct kfd_process *p) -{ - void *backing_store; - struct kfd_signal_page *page; - - page = kzalloc_obj(*page); - if (!page) - return NULL; - - backing_store = (void *) __get_free_pages(GFP_KERNEL, - get_order(KFD_SIGNAL_EVENT_LIMIT * 8)); - if (!backing_store) - goto fail_alloc_signal_store; - - /* Initialize all events to unsignaled */ - memset(backing_store, (uint8_t) UNSIGNALED_EVENT_SLOT, - KFD_SIGNAL_EVENT_LIMIT * 8); - - page->kernel_address = backing_store; - page->need_to_free_pages = true; - pr_debug("Allocated new event signal page at %p, for process %p\n", - page, p); - - return page; - -fail_alloc_signal_store: - kfree(page); - return NULL; -} - static int allocate_event_notification_slot(struct kfd_process *p, struct kfd_event *ev, const int *restore_id) { int id; - if (!p->signal_page) { - p->signal_page = allocate_signal_page(p); - if (!p->signal_page) - return -ENOMEM; - /* Oldest user mode expects 256 event slots */ - p->signal_mapped_size = 256*8; - } + /* + * The signal page is allocated in user mode and mapped to the kernel + * via the event_page_offset of the create event IOCTL. Without it no + * signal events can be created. + */ + if (!p->signal_page) + return -ENOMEM; if (restore_id) { id = idr_alloc(&p->event_idr, ev, *restore_id, *restore_id + 1, @@ -123,7 +77,7 @@ static int allocate_event_notification_slot(struct kfd_process *p, return id; ev->event_id = id; - page_slots(p->signal_page)[id] = UNSIGNALED_EVENT_SLOT; + p->signal_page[id] = UNSIGNALED_EVENT_SLOT; return 0; } @@ -169,7 +123,7 @@ static struct kfd_event *lookup_signaled_event_by_partial_id( */ if (bits > 31 || (1U << bits) >= KFD_SIGNAL_EVENT_LIMIT) { if (signal_mailbox_updated && - page_slots(p->signal_page)[id] == UNSIGNALED_EVENT_SLOT) + p->signal_page[id] == UNSIGNALED_EVENT_SLOT) return NULL; return idr_find(&p->event_idr, id); @@ -179,7 +133,7 @@ static struct kfd_event *lookup_signaled_event_by_partial_id( * and find the first one that has signaled. */ for (ev = NULL; id < KFD_SIGNAL_EVENT_LIMIT && !ev; id += 1U << bits) { - if (page_slots(p->signal_page)[id] == UNSIGNALED_EVENT_SLOT) + if (p->signal_page[id] == UNSIGNALED_EVENT_SLOT) continue; ev = idr_find(&p->event_idr, id); @@ -210,10 +164,8 @@ static int create_signal_event(struct file *devkfd, struct kfd_process *p, p->signal_event_count++; - ev->user_signal_address = &p->signal_page->user_address[ev->event_id]; - pr_debug("Signal event number %zu created with id %d, address %p\n", - p->signal_event_count, ev->event_id, - ev->user_signal_address); + pr_debug("Signal event number %zu created with id %d\n", + p->signal_event_count, ev->event_id); return 0; } @@ -293,26 +245,9 @@ static void destroy_events(struct kfd_process *p) mutex_destroy(&p->event_mutex); } -/* - * We assume that the process is being destroyed and there is no need to - * unmap the pages or keep bookkeeping data in order. - */ -static void shutdown_signal_page(struct kfd_process *p) -{ - struct kfd_signal_page *page = p->signal_page; - - if (page) { - if (page->need_to_free_pages) - free_pages((unsigned long)page->kernel_address, - get_order(KFD_SIGNAL_EVENT_LIMIT * 8)); - kfree(page); - } -} - void kfd_event_free_process(struct kfd_process *p) { destroy_events(p); - shutdown_signal_page(p); } static bool event_can_be_gpu_signaled(const struct kfd_event *ev) @@ -329,8 +264,6 @@ static bool event_can_be_cpu_signaled(const struct kfd_event *ev) static int kfd_event_page_set(struct kfd_process *p, void *kernel_address, uint64_t size, uint64_t user_handle) { - struct kfd_signal_page *page; - if (p->signal_page) return -EBUSY; @@ -340,17 +273,11 @@ static int kfd_event_page_set(struct kfd_process *p, void *kernel_address, return -EINVAL; } - page = kzalloc_obj(*page); - if (!page) - return -ENOMEM; - /* Initialize all events to unsignaled */ memset(kernel_address, (uint8_t) UNSIGNALED_EVENT_SLOT, KFD_SIGNAL_EVENT_LIMIT * 8); - page->kernel_address = kernel_address; - - p->signal_page = page; + p->signal_page = kernel_address; p->signal_mapped_size = size; p->signal_handle = user_handle; return 0; @@ -387,7 +314,8 @@ int kfd_kmap_event_page(struct kfd_process *p, uint64_t event_page_offset) return -EINVAL; } - err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel(mem, &kern_addr, &size); + err = amdgpu_amdkfd_gpuvm_map_bo_to_kernel(mem, &kern_addr, &size, + AMDGPU_GEM_DOMAIN_GTT); if (err) { pr_err("Failed to map event page to kernel\n"); return err; @@ -396,7 +324,7 @@ int kfd_kmap_event_page(struct kfd_process *p, uint64_t event_page_offset) err = kfd_event_page_set(p, kern_addr, size, event_page_offset); if (err) { pr_err("Failed to set event page\n"); - amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(mem); + amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(mem); return err; } return err; @@ -717,7 +645,7 @@ int kfd_reset_event(struct kfd_process *p, uint32_t event_id) static void acknowledge_signal(struct kfd_process *p, struct kfd_event *ev) { - WRITE_ONCE(page_slots(p->signal_page)[ev->event_id], UNSIGNALED_EVENT_SLOT); + WRITE_ONCE(p->signal_page[ev->event_id], UNSIGNALED_EVENT_SLOT); } static void set_event_from_interrupt(struct kfd_process *p, @@ -760,7 +688,7 @@ void kfd_signal_event_interrupt(u32 pasid, uint32_t partial_id, * in the interrupt payload was invalid and do an * exhaustive search of signaled events. */ - uint64_t *slots = page_slots(p->signal_page); + uint64_t *slots = p->signal_page; uint32_t id; if (valid_id_bits) @@ -1068,51 +996,6 @@ int kfd_wait_on_events(struct kfd_process *p, return ret; } -int kfd_event_mmap(struct kfd_process *p, struct vm_area_struct *vma) -{ - unsigned long pfn; - struct kfd_signal_page *page; - int ret; - - /* check required size doesn't exceed the allocated size */ - if (get_order(KFD_SIGNAL_EVENT_LIMIT * 8) < - get_order(vma->vm_end - vma->vm_start)) { - pr_err("Event page mmap requested illegal size\n"); - return -EINVAL; - } - - page = p->signal_page; - if (!page) { - /* Probably KFD bug, but mmap is user-accessible. */ - pr_debug("Signal page could not be found\n"); - return -EINVAL; - } - - pfn = __pa(page->kernel_address); - pfn >>= PAGE_SHIFT; - - vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_NORESERVE - | VM_DONTDUMP | VM_PFNMAP); - - pr_debug("Mapping signal page\n"); - pr_debug(" start user address == 0x%08lx\n", vma->vm_start); - pr_debug(" end user address == 0x%08lx\n", vma->vm_end); - pr_debug(" pfn == 0x%016lX\n", pfn); - pr_debug(" vm_flags == 0x%08lX\n", vma->vm_flags); - pr_debug(" size == 0x%08lX\n", - vma->vm_end - vma->vm_start); - - page->user_address = (uint64_t __user *)vma->vm_start; - - /* mapping the page to user process */ - ret = remap_pfn_range(vma, vma->vm_start, pfn, - vma->vm_end - vma->vm_start, vma->vm_page_prot); - if (!ret) - p->signal_mapped_size = vma->vm_end - vma->vm_start; - - return ret; -} - /* * Assumes that p is not going away. */ @@ -1338,6 +1221,71 @@ void kfd_signal_reset_event(struct kfd_node *dev) srcu_read_unlock(&kfd_processes_srcu, idx); } +/* + * Per-process opt-in for poison-consumption SIGBUS handling. + * + * Default: kernel sends SIGBUS to the process immediately when poison is + * consumed, in addition to delivering the KFD HW/MEMORY exception events. + * + * Userspace (ROCr) can opt-in per-process via the + * DRM_IOCTL_AMDGPU_PROC_OPTIONS / AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY + * option. This lets the app's registered system-event callback handle the + * RAS error first, instead of being killed by SIGBUS. + * + * Encoded value (stored on the kfd_process): + * 0 - default: SIGBUS immediately (no opt-in) + * 0xFFFFFFFF - opt-in, never escalate to SIGBUS + * N (other) - opt-in, escalate to SIGBUS after N ms if app does not + * handle the error in time (safety timeout) + */ + +void kfd_signal_sigbus_delayed_fn(struct work_struct *work) +{ + struct kfd_process *p = container_of(to_delayed_work(work), + struct kfd_process, signal_work); + + if (p->lead_thread) + send_sig(SIGBUS, p->lead_thread, 0); + + kfd_unref_process(p); +} + +static void kfd_signal_sigbus_with_delay(struct kfd_node *dev, + struct kfd_process *p) +{ + u32 delay_ms = atomic_read(&p->kfd_sigbus_delay_ms); + + if (delay_ms == AMDGPU_PROC_OPTIONS_KFD_SIGBUS_DELAY_DISABLED) { + dev_info(dev->adev->dev, + "SIGBUS suppressed for process %s(pid:%d): app opted in to handle RAS error\n", + p->lead_thread->comm, p->lead_thread->pid); + return; + } + + if (delay_ms == 0) + goto send_now; + + /* + * Take an extra reference for the delayed worker. If the work is + * already pending (e.g. another device of this process consumed poison + * just before), drop the reference and skip rescheduling - the process + * only needs to be notified once. + */ + kref_get(&p->ref); + if (!schedule_delayed_work(&p->signal_work, msecs_to_jiffies(delay_ms))) { + kfd_unref_process(p); + return; + } + + dev_info(dev->adev->dev, + "Deferring SIGBUS to process %s(pid:%d) by %u ms (RAS error opt-in safety timeout)\n", + p->lead_thread->comm, p->lead_thread->pid, delay_ms); + return; + +send_now: + send_sig(SIGBUS, p->lead_thread, 0); +} + void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid) { struct kfd_process *p = kfd_lookup_process_by_pasid(pasid, NULL); @@ -1392,7 +1340,7 @@ void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid) rcu_read_unlock(); /* user application will handle SIGBUS signal */ - send_sig(SIGBUS, p->lead_thread, 0); + kfd_signal_sigbus_with_delay(dev, p); kfd_unref_process(p); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_events.h b/drivers/gpu/drm/amd/amdkfd/kfd_events.h index 1dc21c13833b..827a2c7d7721 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_events.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_events.h @@ -49,7 +49,6 @@ #define UNSIGNALED_EVENT_SLOT ((uint64_t)-1) struct kfd_event_waiter; -struct signal_page; struct kfd_event { u32 event_id; @@ -63,9 +62,6 @@ struct kfd_event { spinlock_t lock; wait_queue_head_t wq; /* List of event waiters. */ - /* Only for signal events. */ - uint64_t __user *user_signal_address; - /* type specific data */ union { struct kfd_hsa_memory_exception_data memory_exception_data; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c index 226e76ae0be7..7cd236c1ff75 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_migrate.c @@ -128,7 +128,7 @@ svm_migrate_copy_memory_gart(struct amdgpu_device *adev, dma_addr_t *sys, enum MIGRATION_COPY_DIR direction, struct dma_fence **mfence) { - const u64 GTT_MAX_PAGES = AMDGPU_GTT_MAX_TRANSFER_SIZE; + const u64 GTT_MAX_PAGES = (AMDGPU_GTT_MAX_TRANSFER_SIZE >> PAGE_SHIFT); struct amdgpu_ring *ring; struct amdgpu_ttm_buffer_entity *entity; u64 gart_s, gart_d; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index 723b725d20b8..9b7859a77950 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -315,3 +315,19 @@ bool kfd_check_hiq_mqd_doorbell_id(struct kfd_node *node, uint32_t doorbell_id, return false; } + +bool mqd_on_vram(struct amdgpu_device *adev) +{ + if (adev->apu_prefer_gtt) + return false; + + switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { + case IP_VERSION(9, 4, 2): + case IP_VERSION(9, 4, 3): + case IP_VERSION(9, 4, 4): + case IP_VERSION(9, 5, 0): + return true; + default: + return false; + } +} diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h index 06ca6235ff1b..59eff3389d39 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h @@ -127,6 +127,7 @@ struct mqd_manager { struct mutex mqd_mutex; struct kfd_node *dev; uint32_t mqd_size; + uint32_t ctl_stack_size; }; struct mqd_user_context_save_area_header { @@ -201,4 +202,6 @@ uint64_t kfd_mqd_stride(struct mqd_manager *mm, struct queue_properties *q); bool kfd_check_hiq_mqd_doorbell_id(struct kfd_node *node, uint32_t doorbell_id, uint32_t inst); +bool mqd_on_vram(struct amdgpu_device *adev); + #endif /* KFD_MQD_MANAGER_H_ */ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 8e8ec266ca46..e034da638c07 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -203,8 +203,8 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, * more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control = min(0xA, - ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA, + ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0; m->cp_hqd_eop_base_addr_lo = lower_32_bits(q->eop_ring_buffer_address >> 8); m->cp_hqd_eop_base_addr_hi = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index fff137e00b5e..350fcbbba4b2 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -241,8 +241,8 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, * more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control = min(0xA, - ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA, + ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0; m->cp_hqd_eop_base_addr_lo = lower_32_bits(q->eop_ring_buffer_address >> 8); m->cp_hqd_eop_base_addr_hi = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c index 8c815f129614..7c387fa90076 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12.c @@ -216,8 +216,8 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, * more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control = min(0xA, - ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA, + ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0; m->cp_hqd_eop_base_addr_lo = lower_32_bits(q->eop_ring_buffer_address >> 8); m->cp_hqd_eop_base_addr_hi = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c index 475589b924e9..431a940f91f3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v12_1.c @@ -294,8 +294,8 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, * more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control = min(0xA, - ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1); + m->cp_hqd_eop_control = q->eop_ring_buffer_size ? min(0xA, + ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1) : 0; m->cp_hqd_eop_base_addr_lo = lower_32_bits(q->eop_ring_buffer_address >> 8); m->cp_hqd_eop_base_addr_hi = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index 17bfb419b202..75e5a9f67d50 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -27,6 +27,7 @@ #include #include "kfd_priv.h" #include "kfd_mqd_manager.h" +#include "kfd_topology.h" #include "v9_structs.h" #include "gc/gc_9_0_offset.h" #include "gc/gc_9_0_sh_mask.h" @@ -115,20 +116,6 @@ static void set_priority(struct v9_mqd *m, struct queue_properties *q) m->cp_hqd_pipe_priority = pipe_priority_map[q->priority]; } -static bool mqd_on_vram(struct amdgpu_device *adev) -{ - if (adev->apu_prefer_gtt) - return false; - - switch (amdgpu_ip_version(adev, GC_HWIP, 0)) { - case IP_VERSION(9, 4, 3): - case IP_VERSION(9, 5, 0): - return true; - default: - return false; - } -} - static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, struct queue_properties *q) { @@ -411,8 +398,11 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack_size) { struct v9_mqd *m = get_mqd(mqd); + u32 per_xcc_size; - if (check_mul_overflow(m->cp_hqd_cntl_stack_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size)) + per_xcc_size = min_t(u32, m->cp_hqd_cntl_stack_size, mm->ctl_stack_size); + + if (check_mul_overflow(per_xcc_size, NUM_XCC(mm->dev->xcc_mask), ctl_stack_size)) return -EINVAL; return 0; @@ -421,13 +411,15 @@ static int get_checkpoint_info(struct mqd_manager *mm, void *mqd, u32 *ctl_stack static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst) { struct v9_mqd *m; + u32 ctl_stack_copy_size; /* Control stack is located one page after MQD. */ void *ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE); m = get_mqd(mqd); + ctl_stack_copy_size = min_t(u32, m->cp_hqd_cntl_stack_size, mm->ctl_stack_size); memcpy(mqd_dst, m, sizeof(struct v9_mqd)); - memcpy(ctl_stack_dst, ctl_stack, m->cp_hqd_cntl_stack_size); + memcpy(ctl_stack_dst, ctl_stack, ctl_stack_copy_size); } static void checkpoint_mqd_v9_4_3(struct mqd_manager *mm, @@ -436,15 +428,19 @@ static void checkpoint_mqd_v9_4_3(struct mqd_manager *mm, void *ctl_stack_dst) { struct v9_mqd *m; + u32 ctl_stack_stride; int xcc; uint64_t size = get_mqd(mqd)->cp_mqd_stride_size; + ctl_stack_stride = min_t(u32, get_mqd(mqd)->cp_hqd_cntl_stack_size, + mm->ctl_stack_size); + for (xcc = 0; xcc < NUM_XCC(mm->dev->xcc_mask); xcc++) { m = get_mqd(mqd + size * xcc); checkpoint_mqd(mm, m, (uint8_t *)mqd_dst + sizeof(*m) * xcc, - (uint8_t *)ctl_stack_dst + m->cp_hqd_cntl_stack_size * xcc); + (uint8_t *)ctl_stack_dst + ctl_stack_stride * xcc); } } @@ -998,6 +994,15 @@ struct mqd_manager *mqd_manager_init_v9(enum KFD_MQD_TYPE type, mqd->is_occupied = kfd_is_occupied_cp; mqd->get_checkpoint_info = get_checkpoint_info; mqd->mqd_size = sizeof(struct v9_mqd); + if (dev->kfd->cwsr_enabled) { + struct kfd_topology_device *topo_dev; + + topo_dev = kfd_topology_device_by_id(dev->id); + if (topo_dev) + mqd->ctl_stack_size = + ALIGN(topo_dev->node_props.ctl_stack_size, + AMDGPU_GPU_PAGE_SIZE); + } mqd->mqd_stride = mqd_stride_v9; #if defined(CONFIG_DEBUG_FS) mqd->debugfs_show_mqd = debugfs_show_mqd; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index c86779af323b..60b87a500698 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -214,8 +214,8 @@ static void __update_mqd(struct mqd_manager *mm, void *mqd, * more than (EOP entry count - 1) so a queue size of 0x800 dwords * is safe, giving a maximum field value of 0xA. */ - m->cp_hqd_eop_control |= min(0xA, - order_base_2(q->eop_ring_buffer_size / 4) - 1); + m->cp_hqd_eop_control |= q->eop_ring_buffer_size ? min(0xA, + order_base_2(q->eop_ring_buffer_size / 4) - 1) : 0; m->cp_hqd_eop_base_addr_lo = lower_32_bits(q->eop_ring_buffer_address >> 8); m->cp_hqd_eop_base_addr_hi = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index acd0e41e744c..90f010cbe54e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -952,11 +952,32 @@ struct kfd_process { struct idr event_idr; /* Event page */ u64 signal_handle; - struct kfd_signal_page *signal_page; + /* + * Each signal event needs a 64-bit signal slot where the signaler will + * write a 1 before sending an interrupt. (This is needed because some + * interrupts do not contain enough spare data bits to identify an + * event.) The signal page is allocated in user mode and mapped to the + * kernel; individual signal events use their event_id as slot index. + */ + uint64_t *signal_page; size_t signal_mapped_size; size_t signal_event_count; bool signal_event_limit_reached; + /** + * @kfd_sigbus_delay_ms: Per-process KFD SIGBUS delivery option for + * poison/RAS events (set via DRM_IOCTL_AMDGPU_PROC_OPTIONS / + * AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY). + * + * 0 - send SIGBUS immediately (default) + * 0xFFFFFFFF - suppress SIGBUS delivery + * other - delay SIGBUS delivery by this many milliseconds + */ + atomic_t kfd_sigbus_delay_ms; + + /* Delayed signal delivery to user */ + struct delayed_work signal_work; + /* Information used for memory eviction */ void *kgd_process_info; /* Eviction fence that is attached to all the BOs of this process. The @@ -1525,7 +1546,6 @@ extern const struct kfd_device_global_init_class device_global_init_class_cik; int kfd_event_init_process(struct kfd_process *p); void kfd_event_free_process(struct kfd_process *p); -int kfd_event_mmap(struct kfd_process *process, struct vm_area_struct *vma); int kfd_wait_on_events(struct kfd_process *p, uint32_t num_events, void __user *data, bool all, uint32_t *user_timeout_ms, @@ -1554,6 +1574,7 @@ void kfd_signal_vm_fault_event(struct kfd_process_device *pdd, void kfd_signal_reset_event(struct kfd_node *dev); void kfd_signal_poison_consumed_event(struct kfd_node *dev, u32 pasid); +void kfd_signal_sigbus_delayed_fn(struct work_struct *work); void kfd_signal_process_terminate_event(struct kfd_process *p); static inline void kfd_flush_tlb(struct kfd_process_device *pdd) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index ca71fa726e32..767c2cc8e29e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -153,6 +153,21 @@ static void kfd_sdma_activity_worker(struct work_struct *work) (q->properties.type != KFD_QUEUE_TYPE_SDMA_XGMI)) continue; + if (dqm->dev->kfd2kgd->hqd_sdma_get_counter) { + val = 0; + ret = dqm->dev->kfd2kgd->hqd_sdma_get_counter( + dqm->dev->adev, q->mqd, + dqm->dev->kfd->device_info.num_sdma_queues_per_engine, + &val); + + if (ret) + pr_debug("Failed to read SDMA queue active counter %i\n", ret); + else + workarea->sdma_activity_counter += val; + + continue; + } + sdma_q = kzalloc_obj(struct temp_sdma_queue_list); if (!sdma_q) { dqm_unlock(dqm); @@ -171,7 +186,7 @@ static void kfd_sdma_activity_worker(struct work_struct *work) * count */ if (list_empty(&sdma_q_list.list)) { - workarea->sdma_activity_counter = pdd->sdma_past_activity_counter; + workarea->sdma_activity_counter += pdd->sdma_past_activity_counter; dqm_unlock(dqm); return; } @@ -721,7 +736,7 @@ static void kfd_process_free_gpuvm(struct kgd_mem *mem, struct kfd_node *dev = pdd->dev; if (kptr && *kptr) { - amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(mem); + amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(mem); *kptr = NULL; } @@ -761,10 +776,16 @@ static int kfd_process_alloc_gpuvm(struct kfd_process_device *pdd, } if (kptr) { - err = amdgpu_amdkfd_gpuvm_map_gtt_bo_to_kernel( - (struct kgd_mem *)*mem, kptr, NULL); + u32 domain; + + if (flags & KFD_IOC_ALLOC_MEM_FLAGS_VRAM) + domain = AMDGPU_GEM_DOMAIN_VRAM; + else + domain = AMDGPU_GEM_DOMAIN_GTT; + err = amdgpu_amdkfd_gpuvm_map_bo_to_kernel((struct kgd_mem *)*mem, + kptr, NULL, domain); if (err) { - pr_debug("Map GTT BO to kernel failed\n"); + pr_debug("Map BO to kernel failed err %d\n", err); goto sync_memory_failed; } } @@ -986,6 +1007,33 @@ struct kfd_process *kfd_create_process(struct task_struct *thread) return process; } +/** + * amdgpu_amdkfd_set_sigbus_delay - Set per-process KFD SIGBUS delay + * @task: task in the target process + * @ms: encoded delay value (0 = immediate, 0xFFFFFFFF = suppress, + * otherwise delay in milliseconds) + * + * Stores the SIGBUS delivery option on the kfd_process associated with + * @task. If the calling process has not opened /dev/kfd yet (no + * kfd_process exists), this is a no-op - the option only applies to + * processes that actually use KFD. + */ +int amdgpu_amdkfd_set_sigbus_delay(struct task_struct *task, u32 ms) +{ + struct kfd_process *p; + + if (!task->mm) + return -EINVAL; + + p = kfd_lookup_process_by_mm(task->mm); + if (!p) + return 0; + + atomic_set(&p->kfd_sigbus_delay_ms, ms); + kfd_unref_process(p); + return 0; +} + static struct kfd_process *find_process_by_mm(const struct mm_struct *mm) { struct kfd_process *process; @@ -1092,7 +1140,7 @@ static void kfd_process_kunmap_signal_bo(struct kfd_process *p) if (!mem) goto out; - amdgpu_amdkfd_gpuvm_unmap_gtt_bo_from_kernel(mem); + amdgpu_amdkfd_gpuvm_unmap_bo_from_kernel(mem); out: mutex_unlock(&p->mutex); @@ -1330,6 +1378,11 @@ void kfd_process_notifier_release_internal(struct kfd_process *p) kfd_process_table_remove(p); cancel_delayed_work_sync(&p->eviction_work); cancel_delayed_work_sync(&p->restore_work); + /* + * If work pending, cancel it and drop the extra ref + */ + if (cancel_delayed_work_sync(&p->signal_work)) + kfd_unref_process(p); /* * Dequeue and destroy user queues, it is not safe for GPU to access @@ -1436,8 +1489,7 @@ static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd) { struct kfd_node *dev = pdd->dev; struct qcm_process_device *qpd = &pdd->qpd; - uint32_t flags = KFD_IOC_ALLOC_MEM_FLAGS_GTT - | KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE + u32 flags = KFD_IOC_ALLOC_MEM_FLAGS_NO_SUBSTITUTE | KFD_IOC_ALLOC_MEM_FLAGS_EXECUTABLE; struct kgd_mem *mem; void *kaddr; @@ -1446,7 +1498,12 @@ static int kfd_process_device_init_cwsr_dgpu(struct kfd_process_device *pdd) if (!dev->kfd->cwsr_enabled || qpd->cwsr_kaddr || !qpd->cwsr_base) return 0; - /* cwsr_base is only set for dGPU */ + if (KFD_GC_VERSION(dev) >= IP_VERSION(9, 4, 2) && !dev->adev->apu_prefer_gtt) + flags |= KFD_IOC_ALLOC_MEM_FLAGS_VRAM; + else + flags |= KFD_IOC_ALLOC_MEM_FLAGS_GTT; + + /* Allocate CWSR TBA/TMA buffers */ ret = kfd_process_alloc_gpuvm(pdd, qpd->cwsr_base, KFD_CWSR_TBA_TMA_SIZE, flags, &mem, &kaddr); if (ret) @@ -1586,6 +1643,7 @@ struct kfd_process *create_process(const struct task_struct *thread, bool primar INIT_DELAYED_WORK(&process->eviction_work, evict_process_worker); INIT_DELAYED_WORK(&process->restore_work, restore_process_worker); + INIT_DELAYED_WORK(&process->signal_work, kfd_signal_sigbus_delayed_fn); process->last_restore_timestamp = get_jiffies_64(); err = kfd_event_init_process(process); if (err) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c index 0ac35789b239..acbdca91cde5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c @@ -1040,7 +1040,13 @@ int kfd_criu_restore_queue(struct kfd_process *p, ctl_stack = mqd + q_data->mqd_size; memset(&qp, 0, sizeof(qp)); - set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->adev->gfx.xcc_mask)); + set_queue_properties_from_criu(&qp, q_data, NUM_XCC(pdd->dev->xcc_mask)); + + ret = kfd_queue_acquire_buffers(pdd, &qp); + if (ret) { + pr_debug("failed to acquire user queue buffers for CRIU\n"); + goto exit; + } ret = kfd_queue_acquire_buffers(pdd, &qp); if (ret) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c index e659cd50eb0b..6a7b4d959541 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_smi_events.c @@ -224,10 +224,10 @@ static void kfd_smi_event_add(struct task_struct *task, struct kfd_node *dev, pid = kfd_smi_task_to_pid(task); - len = snprintf(fifo_in, sizeof(fifo_in), "%x ", event); + len = scnprintf(fifo_in, sizeof(fifo_in), "%x ", event); va_start(args, fmt); - len += vsnprintf(fifo_in + len, sizeof(fifo_in) - len, fmt, args); + len += vscnprintf(fifo_in + len, sizeof(fifo_in) - len, fmt, args); va_end(args); add_event_to_kfifo(pid, dev, event, fifo_in, len); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index 0900bb23349e..30ad10bbd47e 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -3473,7 +3473,13 @@ svm_range_is_valid(struct kfd_process *p, uint64_t start, uint64_t size) unsigned long start_unchg = start; start <<= PAGE_SHIFT; - end = start + (size << PAGE_SHIFT); + + if (size == 0) + return -EINVAL; + + if (check_add_overflow(start, size << PAGE_SHIFT, &end)) + return -EOVERFLOW; + do { vma = vma_lookup(p->mm, start); if (!vma || (vma->vm_flags & device_vma)) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 00517c3d0e6a..35b3abe57b80 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -2013,12 +2013,21 @@ static void kfd_topology_set_capabilities(struct kfd_topology_device *dev) dev->node_props.capability |= HSA_CAP_TRAP_DEBUG_PRECISE_MEMORY_OPERATIONS_SUPPORTED; - if (!amdgpu_sriov_vf(dev->gpu->adev)) + if (KFD_GC_VERSION(dev->gpu) >= IP_VERSION(9, 4, 3) && + !amdgpu_sriov_vf(dev->gpu->adev)) dev->node_props.capability |= HSA_CAP_PER_QUEUE_RESET_SUPPORTED; } else { dev->node_props.debug_prop |= HSA_DBG_WATCH_ADDR_MASK_LO_BIT_GFX10 | HSA_DBG_WATCH_ADDR_MASK_HI_BIT; + /* gfx11 dGPU and gfx12.0 */ + if ((KFD_GC_VERSION(dev->gpu) == IP_VERSION(11, 0, 0) || + KFD_GC_VERSION(dev->gpu) == IP_VERSION(11, 0, 2) || + KFD_GC_VERSION(dev->gpu) == IP_VERSION(11, 0, 3) || + KFD_GC_VERSION(dev->gpu) == IP_VERSION(12, 0, 0) || + KFD_GC_VERSION(dev->gpu) == IP_VERSION(12, 0, 1)) && + !amdgpu_sriov_vf(dev->gpu->adev)) + dev->node_props.capability |= HSA_CAP_PER_QUEUE_RESET_SUPPORTED; if (KFD_GC_VERSION(dev->gpu) >= IP_VERSION(12, 0, 0)) dev->node_props.capability |= diff --git a/drivers/gpu/drm/amd/amdxcp/amdgpu_xcp_drv.c b/drivers/gpu/drm/amd/amdxcp/amdgpu_xcp_drv.c index 995cae6be144..84e13537a7ba 100644 --- a/drivers/gpu/drm/amd/amdxcp/amdgpu_xcp_drv.c +++ b/drivers/gpu/drm/amd/amdxcp/amdgpu_xcp_drv.c @@ -45,7 +45,7 @@ static const struct drm_driver amdgpu_xcp_driver = { .minor = 0, }; -static int8_t pdev_num; +static u8 pdev_num; static struct xcp_device *xcp_dev[MAX_XCP_PLATFORM_DEVICE]; static DEFINE_MUTEX(xcp_mutex); @@ -56,6 +56,11 @@ int amdgpu_xcp_drm_dev_alloc(struct drm_device **ddev) char *dev_name; int ret, i; + if (!ddev) + return -EINVAL; + + BUILD_BUG_ON(MAX_XCP_PLATFORM_DEVICE >= U8_MAX); + guard(mutex)(&xcp_mutex); if (pdev_num >= MAX_XCP_PLATFORM_DEVICE) @@ -105,7 +110,7 @@ int amdgpu_xcp_drm_dev_alloc(struct drm_device **ddev) } EXPORT_SYMBOL(amdgpu_xcp_drm_dev_alloc); -static void free_xcp_dev(int8_t index) +static void free_xcp_dev(uint8_t index) { if ((index < MAX_XCP_PLATFORM_DEVICE) && (xcp_dev[index])) { struct platform_device *pdev = xcp_dev[index]->pdev; @@ -114,17 +119,18 @@ static void free_xcp_dev(int8_t index) platform_device_unregister(pdev); xcp_dev[index] = NULL; - pdev_num--; + if (pdev_num > 0) + pdev_num--; } } void amdgpu_xcp_drm_dev_free(struct drm_device *ddev) { - int8_t i; + uint8_t i; guard(mutex)(&xcp_mutex); - for (i = 0; i < MAX_XCP_PLATFORM_DEVICE; i++) { + for (i = 0; pdev_num && i < MAX_XCP_PLATFORM_DEVICE; i++) { if ((xcp_dev[i]) && (&xcp_dev[i]->drm == ddev)) { free_xcp_dev(i); break; @@ -135,7 +141,7 @@ EXPORT_SYMBOL(amdgpu_xcp_drm_dev_free); void amdgpu_xcp_drv_release(void) { - int8_t i; + uint8_t i; guard(mutex)(&xcp_mutex); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index 54a93e4255b3..d83878e35b61 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -41,7 +41,11 @@ AMDGPUDM = \ amdgpu_dm_quirks.o \ amdgpu_dm_wb.o \ amdgpu_dm_colorop.o \ - amdgpu_dm_ism.o + amdgpu_dm_ism.o \ + amdgpu_dm_backlight.o \ + amdgpu_dm_audio.o \ + amdgpu_dm_dmub.o \ + amdgpu_dm_connector.o ifdef CONFIG_DRM_AMD_DC_FP AMDGPUDM += dc_fpu.o diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index d2dcef74625c..67b825cbb88f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -66,6 +66,11 @@ #endif #include "amdgpu_dm_psr.h" #include "amdgpu_dm_replay.h" +#include "amdgpu_dm_backlight.h" +#include "amdgpu_dm_audio.h" +#include "amdgpu_dm_dmub.h" +#include "amdgpu_dm_connector.h" +#include "amdgpu_dm_kunit_helpers.h" #include "ivsrcid/ivsrcid_vislands30.h" @@ -94,7 +99,6 @@ #include #include #include -#include #include #include @@ -107,60 +111,9 @@ #include "modules/inc/mod_power.h" #include "modules/power/power_helpers.h" -static_assert(AMDGPU_DMUB_NOTIFICATION_MAX == DMUB_NOTIFICATION_MAX, "AMDGPU_DMUB_NOTIFICATION_MAX mismatch"); - -#define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); -#define FIRMWARE_SIENNA_CICHLID_DMUB "amdgpu/sienna_cichlid_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID_DMUB); -#define FIRMWARE_NAVY_FLOUNDER_DMUB "amdgpu/navy_flounder_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER_DMUB); -#define FIRMWARE_GREEN_SARDINE_DMUB "amdgpu/green_sardine_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE_DMUB); -#define FIRMWARE_VANGOGH_DMUB "amdgpu/vangogh_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB); -#define FIRMWARE_DIMGREY_CAVEFISH_DMUB "amdgpu/dimgrey_cavefish_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB); -#define FIRMWARE_BEIGE_GOBY_DMUB "amdgpu/beige_goby_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB); -#define FIRMWARE_YELLOW_CARP_DMUB "amdgpu/yellow_carp_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB); -#define FIRMWARE_DCN_314_DMUB "amdgpu/dcn_3_1_4_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_314_DMUB); -#define FIRMWARE_DCN_315_DMUB "amdgpu/dcn_3_1_5_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_315_DMUB); -#define FIRMWARE_DCN316_DMUB "amdgpu/dcn_3_1_6_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN316_DMUB); - -#define FIRMWARE_DCN_V3_2_0_DMCUB "amdgpu/dcn_3_2_0_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_0_DMCUB); -#define FIRMWARE_DCN_V3_2_1_DMCUB "amdgpu/dcn_3_2_1_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_1_DMCUB); - -#define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin" MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU); - -#define FIRMWARE_NAVI12_DMCU "amdgpu/navi12_dmcu.bin" MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU); -#define FIRMWARE_DCN_35_DMUB "amdgpu/dcn_3_5_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_35_DMUB); - -#define FIRMWARE_DCN_351_DMUB "amdgpu/dcn_3_5_1_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_351_DMUB); - -#define FIRMWARE_DCN_36_DMUB "amdgpu/dcn_3_6_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB); - -#define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB); - -#define FIRMWARE_DCN_42_DMUB "amdgpu/dcn_4_2_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_42_DMUB); - -#define FIRMWARE_DCN_42B_DMUB "amdgpu/dcn_4_2_1_dmcub.bin" -MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB); - /** * DOC: overview * @@ -174,46 +127,7 @@ MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB); /* basic init/fini API */ static int amdgpu_dm_init(struct amdgpu_device *adev); static void amdgpu_dm_fini(struct amdgpu_device *adev); -static bool is_freesync_video_mode(const struct drm_display_mode *mode, struct amdgpu_dm_connector *aconnector); static void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state); -static struct amdgpu_i2c_adapter * -create_i2c(struct ddc_service *ddc_service, bool oem); - -static enum drm_mode_subconnector get_subconnector_type(struct dc_link *link) -{ - switch (link->dpcd_caps.dongle_type) { - case DISPLAY_DONGLE_NONE: - return DRM_MODE_SUBCONNECTOR_Native; - case DISPLAY_DONGLE_DP_VGA_CONVERTER: - return DRM_MODE_SUBCONNECTOR_VGA; - case DISPLAY_DONGLE_DP_DVI_CONVERTER: - case DISPLAY_DONGLE_DP_DVI_DONGLE: - return DRM_MODE_SUBCONNECTOR_DVID; - case DISPLAY_DONGLE_DP_HDMI_CONVERTER: - case DISPLAY_DONGLE_DP_HDMI_DONGLE: - return DRM_MODE_SUBCONNECTOR_HDMIA; - case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE: - default: - return DRM_MODE_SUBCONNECTOR_Unknown; - } -} - -static void update_subconnector_property(struct amdgpu_dm_connector *aconnector) -{ - struct dc_link *link = aconnector->dc_link; - struct drm_connector *connector = &aconnector->base; - enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown; - - if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) - return; - - if (aconnector->dc_sink) - subconnector = get_subconnector_type(link); - - drm_object_property_set_value(&connector->base, - connector->dev->mode_config.dp_subconnector_property, - subconnector); -} /* * initializes drm_device display related structures, based on the information @@ -226,32 +140,23 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev); /* removes and deallocates the drm structures, created by the above function */ static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm); -static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, - struct amdgpu_dm_connector *amdgpu_dm_connector, - u32 link_index, - struct amdgpu_encoder *amdgpu_encoder); -static int amdgpu_dm_encoder_init(struct drm_device *dev, - struct amdgpu_encoder *aencoder, - uint32_t link_index); - -static int amdgpu_dm_connector_get_modes(struct drm_connector *connector); - static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *state); static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state); +static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context); static int amdgpu_dm_atomic_check(struct drm_device *dev, struct drm_atomic_commit *state); -static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector); -static void handle_hpd_rx_irq(void *param); - -static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, - int bl_idx, - u32 user_brightness); - -static bool +STATIC_IFN_KUNIT bool is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state, struct drm_crtc_state *new_crtc_state); + +static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc) +{ + if (dc->ctx->dmub_srv && !dc->ctx->dmub_srv->idle_exit_counter) + dc_exit_ips_for_hw_access(dc); +} + /* * dm_vblank_get_counter * @@ -332,40 +237,14 @@ static int dm_wait_for_idle(struct amdgpu_ip_block *ip_block) return 0; } -static bool dm_check_soft_reset(struct amdgpu_ip_block *ip_block) -{ - return false; -} - static int dm_soft_reset(struct amdgpu_ip_block *ip_block) { /* XXX todo */ return 0; } -static struct amdgpu_crtc * -get_crtc_by_otg_inst(struct amdgpu_device *adev, - int otg_inst) -{ - struct drm_device *dev = adev_to_drm(adev); - struct drm_crtc *crtc; - struct amdgpu_crtc *amdgpu_crtc; - - if (WARN_ON(otg_inst == -1)) - return adev->mode_info.crtcs[0]; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - amdgpu_crtc = to_amdgpu_crtc(crtc); - - if (amdgpu_crtc->otg_inst == otg_inst) - return amdgpu_crtc; - } - - return NULL; -} - -static inline bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state, - struct dm_crtc_state *new_state) +STATIC_IFN_KUNIT bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state, + struct dm_crtc_state *new_state) { if (new_state->stream->adjust.timing_adjust_pending) return true; @@ -376,13 +255,14 @@ static inline bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state, else return false; } +EXPORT_IF_KUNIT(is_dc_timing_adjust_needed); /* * DC will program planes with their z-order determined by their ordering * in the dc_surface_updates array. This comparator is used to sort them * by descending zpos. */ -static int dm_plane_layer_index_cmp(const void *a, const void *b) +STATIC_IFN_KUNIT int dm_plane_layer_index_cmp(const void *a, const void *b) { const struct dc_surface_update *sa = (struct dc_surface_update *)a; const struct dc_surface_update *sb = (struct dc_surface_update *)b; @@ -390,6 +270,7 @@ static int dm_plane_layer_index_cmp(const void *a, const void *b) /* Sort by descending dc_plane layer_index (i.e. normalized_zpos) */ return sb->surface->layer_index - sa->surface->layer_index; } +EXPORT_IF_KUNIT(dm_plane_layer_index_cmp); /** * update_planes_and_stream_adapter() - Send planes to be updated in DC @@ -430,633 +311,6 @@ static inline bool update_planes_and_stream_adapter(struct dc *dc, stream_update); } -/** - * dm_pflip_high_irq() - Handle pageflip interrupt - * @interrupt_params: ignored - * - * Handles the pageflip interrupt by notifying all interested parties - * that the pageflip has been completed. - */ -static void dm_pflip_high_irq(void *interrupt_params) -{ - struct amdgpu_crtc *amdgpu_crtc; - struct common_irq_params *irq_params = interrupt_params; - struct amdgpu_device *adev = irq_params->adev; - struct drm_device *dev = adev_to_drm(adev); - unsigned long flags; - struct drm_pending_vblank_event *e; - u32 vpos, hpos, v_blank_start, v_blank_end; - bool vrr_active; - - amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP); - - /* IRQ could occur when in initial stage */ - /* TODO work and BO cleanup */ - if (amdgpu_crtc == NULL) { - drm_dbg_state(dev, "CRTC is null, returning.\n"); - return; - } - - spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); - - if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) { - drm_dbg_state(dev, - "amdgpu_crtc->pflip_status = %d != AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p]\n", - amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED, - amdgpu_crtc->crtc_id, amdgpu_crtc); - spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); - return; - } - - /* page flip completed. */ - e = amdgpu_crtc->event; - amdgpu_crtc->event = NULL; - - WARN_ON(!e); - - vrr_active = amdgpu_dm_crtc_vrr_active_irq(amdgpu_crtc); - - /* Fixed refresh rate, or VRR scanout position outside front-porch? */ - if (!vrr_active || - !dc_stream_get_scanoutpos(amdgpu_crtc->dm_irq_params.stream, &v_blank_start, - &v_blank_end, &hpos, &vpos) || - (vpos < v_blank_start)) { - /* Update to correct count and vblank timestamp if racing with - * vblank irq. This also updates to the correct vblank timestamp - * even in VRR mode, as scanout is past the front-porch atm. - */ - drm_crtc_accurate_vblank_count(&amdgpu_crtc->base); - - /* Wake up userspace by sending the pageflip event with proper - * count and timestamp of vblank of flip completion. - */ - if (e) { - drm_crtc_send_vblank_event(&amdgpu_crtc->base, e); - - /* Event sent, so done with vblank for this flip */ - drm_crtc_vblank_put(&amdgpu_crtc->base); - } - } else if (e) { - /* VRR active and inside front-porch: vblank count and - * timestamp for pageflip event will only be up to date after - * drm_crtc_handle_vblank() has been executed from late vblank - * irq handler after start of back-porch (vline 0). We queue the - * pageflip event for send-out by drm_crtc_handle_vblank() with - * updated timestamp and count, once it runs after us. - * - * We need to open-code this instead of using the helper - * drm_crtc_arm_vblank_event(), as that helper would - * call drm_crtc_accurate_vblank_count(), which we must - * not call in VRR mode while we are in front-porch! - */ - - /* sequence will be replaced by real count during send-out. */ - e->sequence = drm_crtc_vblank_count(&amdgpu_crtc->base); - e->pipe = amdgpu_crtc->crtc_id; - - list_add_tail(&e->base.link, &adev_to_drm(adev)->vblank_event_list); - e = NULL; - } - - /* Keep track of vblank of this flip for flip throttling. We use the - * cooked hw counter, as that one incremented at start of this vblank - * of pageflip completion, so last_flip_vblank is the forbidden count - * for queueing new pageflips if vsync + VRR is enabled. - */ - amdgpu_crtc->dm_irq_params.last_flip_vblank = - amdgpu_get_vblank_counter_kms(&amdgpu_crtc->base); - - amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE; - spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); - - drm_dbg_state(dev, - "crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n", - amdgpu_crtc->crtc_id, amdgpu_crtc, vrr_active, (int)!e); -} - -static void dm_handle_vmin_vmax_update(struct work_struct *offload_work) -{ - struct vupdate_offload_work *work = container_of(offload_work, struct vupdate_offload_work, work); - struct amdgpu_device *adev = work->adev; - struct dc_stream_state *stream = work->stream; - struct dc_crtc_timing_adjust *adjust = work->adjust; - - mutex_lock(&adev->dm.dc_lock); - dc_stream_adjust_vmin_vmax(adev->dm.dc, stream, adjust); - mutex_unlock(&adev->dm.dc_lock); - - dc_stream_release(stream); - kfree(work->adjust); - kfree(work); -} - -static void schedule_dc_vmin_vmax(struct amdgpu_device *adev, - struct dc_stream_state *stream, - struct dc_crtc_timing_adjust *adjust) -{ - struct vupdate_offload_work *offload_work = kzalloc_obj(*offload_work, - GFP_NOWAIT); - if (!offload_work) { - drm_dbg_driver(adev_to_drm(adev), "Failed to allocate vupdate_offload_work\n"); - return; - } - - struct dc_crtc_timing_adjust *adjust_copy = kzalloc_obj(*adjust_copy, - GFP_NOWAIT); - if (!adjust_copy) { - drm_dbg_driver(adev_to_drm(adev), "Failed to allocate adjust_copy\n"); - kfree(offload_work); - return; - } - - dc_stream_retain(stream); - memcpy(adjust_copy, adjust, sizeof(*adjust_copy)); - - INIT_WORK(&offload_work->work, dm_handle_vmin_vmax_update); - offload_work->adev = adev; - offload_work->stream = stream; - offload_work->adjust = adjust_copy; - - queue_work(system_percpu_wq, &offload_work->work); -} - -static void dm_vupdate_high_irq(void *interrupt_params) -{ - struct common_irq_params *irq_params = interrupt_params; - struct amdgpu_device *adev = irq_params->adev; - struct amdgpu_crtc *acrtc; - struct drm_device *drm_dev; - struct drm_vblank_crtc *vblank; - ktime_t frame_duration_ns, previous_timestamp; - unsigned long flags; - int vrr_active; - - acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE); - - if (acrtc) { - vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); - drm_dev = acrtc->base.dev; - vblank = drm_crtc_vblank_crtc(&acrtc->base); - previous_timestamp = atomic64_read(&irq_params->previous_timestamp); - frame_duration_ns = vblank->time - previous_timestamp; - - if (frame_duration_ns > 0) { - trace_amdgpu_refresh_rate_track(acrtc->base.index, - frame_duration_ns, - ktime_divns(NSEC_PER_SEC, frame_duration_ns)); - atomic64_set(&irq_params->previous_timestamp, vblank->time); - } - - drm_dbg_vbl(drm_dev, - "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id, - vrr_active); - - /* Core vblank handling is done here after end of front-porch in - * vrr mode, as vblank timestamping will give valid results - * while now done after front-porch. This will also deliver - * page-flip completion events that have been queued to us - * if a pageflip happened inside front-porch. - */ - if (vrr_active && acrtc->dm_irq_params.stream) { - bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; - bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; - bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state - == VRR_STATE_ACTIVE_VARIABLE; - - amdgpu_dm_crtc_handle_vblank(acrtc); - - /* BTR processing for pre-DCE12 ASICs */ - if (adev->family < AMDGPU_FAMILY_AI) { - spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); - mod_freesync_handle_v_update( - adev->dm.freesync_module, - acrtc->dm_irq_params.stream, - &acrtc->dm_irq_params.vrr_params); - - if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { - schedule_dc_vmin_vmax(adev, - acrtc->dm_irq_params.stream, - &acrtc->dm_irq_params.vrr_params.adjust); - } - spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); - } - } - } -} - -/** - * dm_crtc_high_irq() - Handles CRTC interrupt - * @interrupt_params: used for determining the CRTC instance - * - * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK - * event handler. - */ -static void dm_crtc_high_irq(void *interrupt_params) -{ - struct common_irq_params *irq_params = interrupt_params; - struct amdgpu_device *adev = irq_params->adev; - struct drm_writeback_job *job; - struct amdgpu_crtc *acrtc; - unsigned long flags; - int vrr_active; - - acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); - if (!acrtc) - return; - - if (acrtc->wb_conn) { - spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); - - if (acrtc->wb_pending) { - job = list_first_entry_or_null(&acrtc->wb_conn->job_queue, - struct drm_writeback_job, - list_entry); - acrtc->wb_pending = false; - spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); - - if (job) { - unsigned int v_total, refresh_hz; - struct dc_stream_state *stream = acrtc->dm_irq_params.stream; - - v_total = stream->adjust.v_total_max ? - stream->adjust.v_total_max : stream->timing.v_total; - refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz * - 100LL, (v_total * stream->timing.h_total)); - mdelay(1000 / refresh_hz); - - drm_writeback_signal_completion(acrtc->wb_conn, 0); - dc_stream_fc_disable_writeback(adev->dm.dc, - acrtc->dm_irq_params.stream, 0); - } - } else - spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); - } - - vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); - - drm_dbg_vbl(adev_to_drm(adev), - "crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id, - vrr_active, acrtc->dm_irq_params.active_planes); - - /** - * Core vblank handling at start of front-porch is only possible - * in non-vrr mode, as only there vblank timestamping will give - * valid results while done in front-porch. Otherwise defer it - * to dm_vupdate_high_irq after end of front-porch. - */ - if (!vrr_active) - amdgpu_dm_crtc_handle_vblank(acrtc); - - /** - * Following stuff must happen at start of vblank, for crc - * computation and below-the-range btr support in vrr mode. - */ - amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); - - /* BTR updates need to happen before VUPDATE on Vega and above. */ - if (adev->family < AMDGPU_FAMILY_AI) - return; - - spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); - - if (acrtc->dm_irq_params.stream && - acrtc->dm_irq_params.vrr_params.supported) { - bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; - bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; - bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE; - - mod_freesync_handle_v_update(adev->dm.freesync_module, - acrtc->dm_irq_params.stream, - &acrtc->dm_irq_params.vrr_params); - - /* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */ - if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { - schedule_dc_vmin_vmax(adev, acrtc->dm_irq_params.stream, - &acrtc->dm_irq_params.vrr_params.adjust); - } - } - - /* - * If there aren't any active_planes then DCH HUBP may be clock-gated. - * In that case, pageflip completion interrupts won't fire and pageflip - * completion events won't get delivered. Prevent this by sending - * pending pageflip events from here if a flip is still pending. - * - * If any planes are enabled, use dm_pflip_high_irq() instead, to - * avoid race conditions between flip programming and completion, - * which could cause too early flip completion events. - */ - if (adev->family >= AMDGPU_FAMILY_RV && - acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED && - acrtc->dm_irq_params.active_planes == 0) { - if (acrtc->event) { - drm_crtc_send_vblank_event(&acrtc->base, acrtc->event); - acrtc->event = NULL; - drm_crtc_vblank_put(&acrtc->base); - } - acrtc->pflip_status = AMDGPU_FLIP_NONE; - } - - spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); -} - -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) -/** - * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for - * DCN generation ASICs - * @interrupt_params: interrupt parameters - * - * Used to set crc window/read out crc value at vertical line 0 position - */ -static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params) -{ - struct common_irq_params *irq_params = interrupt_params; - struct amdgpu_device *adev = irq_params->adev; - struct amdgpu_crtc *acrtc; - - acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VLINE0); - - if (!acrtc) - return; - - amdgpu_dm_crtc_handle_crc_window_irq(&acrtc->base); -} -#endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */ - -/** - * dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command. - * @adev: amdgpu_device pointer - * @notify: dmub notification structure - * - * Dmub AUX or SET_CONFIG command completion processing callback - * Copies dmub notification to DM which is to be read by AUX command. - * issuing thread and also signals the event to wake up the thread. - */ -static void dmub_aux_setconfig_callback(struct amdgpu_device *adev, - struct dmub_notification *notify) -{ - if (adev->dm.dmub_notify) - memcpy(adev->dm.dmub_notify, notify, sizeof(struct dmub_notification)); - if (notify->type == DMUB_NOTIFICATION_AUX_REPLY) - complete(&adev->dm.dmub_aux_transfer_done); -} - -static void dmub_aux_fused_io_callback(struct amdgpu_device *adev, - struct dmub_notification *notify) -{ - if (!adev || !notify) { - ASSERT(false); - return; - } - - const struct dmub_cmd_fused_request *req = ¬ify->fused_request; - const uint8_t ddc_line = req->u.aux.ddc_line; - - if (ddc_line >= ARRAY_SIZE(adev->dm.fused_io)) { - ASSERT(false); - return; - } - - struct fused_io_sync *sync = &adev->dm.fused_io[ddc_line]; - - static_assert(sizeof(*req) <= sizeof(sync->reply_data), "Size mismatch"); - memcpy(sync->reply_data, req, sizeof(*req)); - complete(&sync->replied); -} - -/** - * dmub_hpd_callback - DMUB HPD interrupt processing callback. - * @adev: amdgpu_device pointer - * @notify: dmub notification structure - * - * Dmub Hpd interrupt processing callback. Gets displayindex through the - * ink index and calls helper to do the processing. - */ -static void dmub_hpd_callback(struct amdgpu_device *adev, - struct dmub_notification *notify) -{ - struct amdgpu_dm_connector *aconnector; - struct amdgpu_dm_connector *hpd_aconnector = NULL; - struct drm_connector *connector; - struct drm_connector_list_iter iter; - struct dc_link *link; - u8 link_index = 0; - struct drm_device *dev; - - if (adev == NULL) - return; - - if (notify == NULL) { - drm_err(adev_to_drm(adev), "DMUB HPD callback notification was NULL"); - return; - } - - if (notify->link_index > adev->dm.dc->link_count) { - drm_err(adev_to_drm(adev), "DMUB HPD index (%u)is abnormal", notify->link_index); - return; - } - - /* Skip DMUB HPD IRQ in suspend/resume. We will probe them later. */ - if (notify->type == DMUB_NOTIFICATION_HPD && adev->in_suspend) { - drm_info(adev_to_drm(adev), "Skip DMUB HPD IRQ callback in suspend/resume\n"); - return; - } - - link_index = notify->link_index; - link = adev->dm.dc->links[link_index]; - dev = adev->dm.ddev; - - drm_connector_list_iter_begin(dev, &iter); - drm_for_each_connector_iter(connector, &iter) { - - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - continue; - - aconnector = to_amdgpu_dm_connector(connector); - if (link && aconnector->dc_link == link) { - if (notify->type == DMUB_NOTIFICATION_HPD) - drm_info(adev_to_drm(adev), "DMUB HPD IRQ callback: link_index=%u\n", link_index); - else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ) - drm_info(adev_to_drm(adev), "DMUB HPD RX IRQ callback: link_index=%u\n", link_index); - else - drm_warn(adev_to_drm(adev), "DMUB Unknown HPD callback type %d, link_index=%u\n", - notify->type, link_index); - - hpd_aconnector = aconnector; - break; - } - } - drm_connector_list_iter_end(&iter); - - if (hpd_aconnector) { - if (notify->type == DMUB_NOTIFICATION_HPD) { - if (hpd_aconnector->dc_link->hpd_status == (notify->hpd_status == DP_HPD_PLUG)) - drm_warn(adev_to_drm(adev), "DMUB reported hpd status unchanged. link_index=%u\n", link_index); - handle_hpd_irq_helper(hpd_aconnector); - } else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ) { - handle_hpd_rx_irq(hpd_aconnector); - } - } -} - -/** - * dmub_hpd_sense_callback - DMUB HPD sense processing callback. - * @adev: amdgpu_device pointer - * @notify: dmub notification structure - * - * HPD sense changes can occur during low power states and need to be - * notified from firmware to driver. - */ -static void dmub_hpd_sense_callback(struct amdgpu_device *adev, - struct dmub_notification *notify) -{ - drm_dbg_driver(adev_to_drm(adev), "DMUB HPD SENSE callback.\n"); -} - -/** - * register_dmub_notify_callback - Sets callback for DMUB notify - * @adev: amdgpu_device pointer - * @type: Type of dmub notification - * @callback: Dmub interrupt callback function - * @dmub_int_thread_offload: offload indicator - * - * API to register a dmub callback handler for a dmub notification - * Also sets indicator whether callback processing to be offloaded. - * to dmub interrupt handling thread - * Return: true if successfully registered, false if there is existing registration - */ -static bool register_dmub_notify_callback(struct amdgpu_device *adev, - enum dmub_notification_type type, - dmub_notify_interrupt_callback_t callback, - bool dmub_int_thread_offload) -{ - if (callback != NULL && type < ARRAY_SIZE(adev->dm.dmub_thread_offload)) { - adev->dm.dmub_callback[type] = callback; - adev->dm.dmub_thread_offload[type] = dmub_int_thread_offload; - } else - return false; - - return true; -} - -static void dm_handle_hpd_work(struct work_struct *work) -{ - struct dmub_hpd_work *dmub_hpd_wrk; - - dmub_hpd_wrk = container_of(work, struct dmub_hpd_work, handle_hpd_work); - - if (!dmub_hpd_wrk->dmub_notify) { - drm_err(adev_to_drm(dmub_hpd_wrk->adev), "dmub_hpd_wrk dmub_notify is NULL"); - return; - } - - if (dmub_hpd_wrk->dmub_notify->type < ARRAY_SIZE(dmub_hpd_wrk->adev->dm.dmub_callback)) { - dmub_hpd_wrk->adev->dm.dmub_callback[dmub_hpd_wrk->dmub_notify->type](dmub_hpd_wrk->adev, - dmub_hpd_wrk->dmub_notify); - } - - kfree(dmub_hpd_wrk->dmub_notify); - kfree(dmub_hpd_wrk); - -} - -static const char *dmub_notification_type_str(enum dmub_notification_type e) -{ - switch (e) { - case DMUB_NOTIFICATION_NO_DATA: - return "NO_DATA"; - case DMUB_NOTIFICATION_AUX_REPLY: - return "AUX_REPLY"; - case DMUB_NOTIFICATION_HPD: - return "HPD"; - case DMUB_NOTIFICATION_HPD_IRQ: - return "HPD_IRQ"; - case DMUB_NOTIFICATION_SET_CONFIG_REPLY: - return "SET_CONFIG_REPLY"; - case DMUB_NOTIFICATION_DPIA_NOTIFICATION: - return "DPIA_NOTIFICATION"; - case DMUB_NOTIFICATION_HPD_SENSE_NOTIFY: - return "HPD_SENSE_NOTIFY"; - case DMUB_NOTIFICATION_FUSED_IO: - return "FUSED_IO"; - default: - return ""; - } -} - -#define DMUB_TRACE_MAX_READ 64 -/** - * dm_dmub_outbox1_low_irq() - Handles Outbox interrupt - * @interrupt_params: used for determining the Outbox instance - * - * Handles the Outbox Interrupt - * event handler. - */ -static void dm_dmub_outbox1_low_irq(void *interrupt_params) -{ - struct dmub_notification notify = {0}; - struct common_irq_params *irq_params = interrupt_params; - struct amdgpu_device *adev = irq_params->adev; - struct amdgpu_display_manager *dm = &adev->dm; - struct dmcub_trace_buf_entry entry = { 0 }; - u32 count = 0; - struct dmub_hpd_work *dmub_hpd_wrk; - - do { - if (dc_dmub_srv_get_dmub_outbox0_msg(dm->dc, &entry)) { - trace_amdgpu_dmub_trace_high_irq(entry.trace_code, entry.tick_count, - entry.param0, entry.param1); - - drm_dbg_driver(adev_to_drm(adev), "trace_code:%u, tick_count:%u, param0:%u, param1:%u\n", - entry.trace_code, entry.tick_count, entry.param0, entry.param1); - } else - break; - - count++; - - } while (count <= DMUB_TRACE_MAX_READ); - - if (count > DMUB_TRACE_MAX_READ) - drm_dbg_driver(adev_to_drm(adev), "Warning : count > DMUB_TRACE_MAX_READ"); - - if (dc_enable_dmub_notifications(adev->dm.dc) && - irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) { - - do { - dc_stat_get_dmub_notification(adev->dm.dc, ¬ify); - if (notify.type >= ARRAY_SIZE(dm->dmub_thread_offload)) { - drm_err(adev_to_drm(adev), "DM: notify type %d invalid!", notify.type); - continue; - } - if (!dm->dmub_callback[notify.type]) { - drm_warn(adev_to_drm(adev), "DMUB notification skipped due to no handler: type=%s\n", - dmub_notification_type_str(notify.type)); - continue; - } - if (dm->dmub_thread_offload[notify.type] == true) { - dmub_hpd_wrk = kzalloc_obj(*dmub_hpd_wrk, - GFP_ATOMIC); - if (!dmub_hpd_wrk) { - drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk"); - return; - } - dmub_hpd_wrk->dmub_notify = kmemdup(¬ify, sizeof(struct dmub_notification), - GFP_ATOMIC); - if (!dmub_hpd_wrk->dmub_notify) { - kfree(dmub_hpd_wrk); - drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk->dmub_notify"); - return; - } - INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); - dmub_hpd_wrk->adev = adev; - queue_work(adev->dm.delayed_hpd_wq, &dmub_hpd_wrk->handle_hpd_work); - } else { - dm->dmub_callback[notify.type](adev, ¬ify); - } - } while (notify.pending_notification); - } -} - static int dm_set_clockgating_state(struct amdgpu_ip_block *ip_block, enum amd_clockgating_state state) { @@ -1073,401 +327,6 @@ static int dm_set_powergating_state(struct amdgpu_ip_block *ip_block, static int dm_early_init(struct amdgpu_ip_block *ip_block); /* Allocate memory for FBC compressed data */ -static void amdgpu_dm_fbc_init(struct drm_connector *connector) -{ - struct amdgpu_device *adev = drm_to_adev(connector->dev); - struct dm_compressor_info *compressor = &adev->dm.compressor; - struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector); - struct drm_display_mode *mode; - unsigned long max_size = 0; - - if (adev->dm.dc->fbc_compressor == NULL) - return; - - if (aconn->dc_link->connector_signal != SIGNAL_TYPE_EDP) - return; - - if (compressor->bo_ptr) - return; - - - list_for_each_entry(mode, &connector->modes, head) { - if (max_size < (unsigned long) mode->htotal * mode->vtotal) - max_size = (unsigned long) mode->htotal * mode->vtotal; - } - - if (max_size) { - int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_GTT, &compressor->bo_ptr, - &compressor->gpu_addr, &compressor->cpu_addr); - - if (r) - drm_err(adev_to_drm(adev), "DM: Failed to initialize FBC\n"); - else { - adev->dm.dc->ctx->fbc_gpu_addr = compressor->gpu_addr; - drm_info(adev_to_drm(adev), "DM: FBC alloc %lu\n", max_size*4); - } - - } - -} - -static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, - int pipe, bool *enabled, - unsigned char *buf, int max_bytes) -{ - struct drm_device *dev = dev_get_drvdata(kdev); - struct amdgpu_device *adev = drm_to_adev(dev); - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; - struct amdgpu_dm_connector *aconnector; - int ret = 0; - - *enabled = false; - - mutex_lock(&adev->dm.audio_lock); - - drm_connector_list_iter_begin(dev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - continue; - - aconnector = to_amdgpu_dm_connector(connector); - if (aconnector->audio_inst != port) - continue; - - *enabled = true; - mutex_lock(&connector->eld_mutex); - ret = drm_eld_size(connector->eld); - memcpy(buf, connector->eld, min(max_bytes, ret)); - mutex_unlock(&connector->eld_mutex); - - break; - } - drm_connector_list_iter_end(&conn_iter); - - mutex_unlock(&adev->dm.audio_lock); - - drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); - - return ret; -} - -static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = { - .get_eld = amdgpu_dm_audio_component_get_eld, -}; - -static int amdgpu_dm_audio_component_bind(struct device *kdev, - struct device *hda_kdev, void *data) -{ - struct drm_device *dev = dev_get_drvdata(kdev); - struct amdgpu_device *adev = drm_to_adev(dev); - struct drm_audio_component *acomp = data; - - acomp->ops = &amdgpu_dm_audio_component_ops; - acomp->dev = kdev; - adev->dm.audio_component = acomp; - - return 0; -} - -static void amdgpu_dm_audio_component_unbind(struct device *kdev, - struct device *hda_kdev, void *data) -{ - struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev)); - struct drm_audio_component *acomp = data; - - acomp->ops = NULL; - acomp->dev = NULL; - adev->dm.audio_component = NULL; -} - -static const struct component_ops amdgpu_dm_audio_component_bind_ops = { - .bind = amdgpu_dm_audio_component_bind, - .unbind = amdgpu_dm_audio_component_unbind, -}; - -static int amdgpu_dm_audio_init(struct amdgpu_device *adev) -{ - int i, ret; - - if (!amdgpu_audio) - return 0; - - adev->mode_info.audio.enabled = true; - - adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count; - - for (i = 0; i < adev->mode_info.audio.num_pins; i++) { - adev->mode_info.audio.pin[i].channels = -1; - adev->mode_info.audio.pin[i].rate = -1; - adev->mode_info.audio.pin[i].bits_per_sample = -1; - adev->mode_info.audio.pin[i].status_bits = 0; - adev->mode_info.audio.pin[i].category_code = 0; - adev->mode_info.audio.pin[i].connected = false; - adev->mode_info.audio.pin[i].id = - adev->dm.dc->res_pool->audios[i]->inst; - adev->mode_info.audio.pin[i].offset = 0; - } - - ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops); - if (ret < 0) - return ret; - - adev->dm.audio_registered = true; - - return 0; -} - -static void amdgpu_dm_audio_fini(struct amdgpu_device *adev) -{ - if (!amdgpu_audio) - return; - - if (!adev->mode_info.audio.enabled) - return; - - if (adev->dm.audio_registered) { - component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops); - adev->dm.audio_registered = false; - } - - /* TODO: Disable audio? */ - - adev->mode_info.audio.enabled = false; -} - -static void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) -{ - struct drm_audio_component *acomp = adev->dm.audio_component; - - if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { - drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin); - - acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, - pin, -1); - } -} - -static int dm_dmub_hw_init(struct amdgpu_device *adev) -{ - const struct dmcub_firmware_header_v1_0 *hdr; - struct dmub_srv *dmub_srv = adev->dm.dmub_srv; - struct dmub_srv_fb_info *fb_info = adev->dm.dmub_fb_info; - const struct firmware *dmub_fw = adev->dm.dmub_fw; - struct dc *dc = adev->dm.dc; - struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu; - struct abm *abm = adev->dm.dc->res_pool->abm; - struct dc_context *ctx = adev->dm.dc->ctx; - struct dmub_srv_hw_params hw_params; - enum dmub_status status; - const unsigned char *fw_inst_const, *fw_bss_data; - u32 i, fw_inst_const_size, fw_bss_data_size; - bool has_hw_support; - - if (!dmub_srv) - /* DMUB isn't supported on the ASIC. */ - return 0; - - if (!fb_info) { - drm_err(adev_to_drm(adev), "No framebuffer info for DMUB service.\n"); - return -EINVAL; - } - - if (!dmub_fw) { - /* Firmware required for DMUB support. */ - drm_err(adev_to_drm(adev), "No firmware provided for DMUB.\n"); - return -EINVAL; - } - - /* initialize register offsets for ASICs with runtime initialization available */ - if (dmub_srv->hw_funcs.init_reg_offsets) - dmub_srv->hw_funcs.init_reg_offsets(dmub_srv, ctx); - - status = dmub_srv_has_hw_support(dmub_srv, &has_hw_support); - if (status != DMUB_STATUS_OK) { - drm_err(adev_to_drm(adev), "Error checking HW support for DMUB: %d\n", status); - return -EINVAL; - } - - if (!has_hw_support) { - drm_info(adev_to_drm(adev), "DMUB unsupported on ASIC\n"); - return 0; - } - - /* Reset DMCUB if it was previously running - before we overwrite its memory. */ - status = dmub_srv_hw_reset(dmub_srv); - if (status != DMUB_STATUS_OK) - drm_warn(adev_to_drm(adev), "Error resetting DMUB HW: %d\n", status); - - hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data; - - fw_inst_const = dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - PSP_HEADER_BYTES_256; - - fw_bss_data = dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - le32_to_cpu(hdr->inst_const_bytes); - - /* Copy firmware and bios info into FB memory. */ - fw_inst_const_size = adev->dm.fw_inst_size; - - fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes); - - /* if adev->firmware.load_type == AMDGPU_FW_LOAD_PSP, - * amdgpu_ucode_init_single_fw will load dmub firmware - * fw_inst_const part to cw0; otherwise, the firmware back door load - * will be done by dm_dmub_hw_init - */ - if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { - memcpy(fb_info->fb[DMUB_WINDOW_0_INST_CONST].cpu_addr, fw_inst_const, - fw_inst_const_size); - } - - if (fw_bss_data_size) - memcpy(fb_info->fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr, - fw_bss_data, fw_bss_data_size); - - /* Copy firmware bios info into FB memory. */ - memcpy(fb_info->fb[DMUB_WINDOW_3_VBIOS].cpu_addr, adev->bios, - adev->bios_size); - - /* Reset regions that need to be reset. */ - memset(fb_info->fb[DMUB_WINDOW_4_MAILBOX].cpu_addr, 0, - fb_info->fb[DMUB_WINDOW_4_MAILBOX].size); - - memset(fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].cpu_addr, 0, - fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].size); - - memset(fb_info->fb[DMUB_WINDOW_6_FW_STATE].cpu_addr, 0, - fb_info->fb[DMUB_WINDOW_6_FW_STATE].size); - - memset(fb_info->fb[DMUB_WINDOW_SHARED_STATE].cpu_addr, 0, - fb_info->fb[DMUB_WINDOW_SHARED_STATE].size); - - /* Initialize hardware. */ - memset(&hw_params, 0, sizeof(hw_params)); - hw_params.soc_fb_info.fb_base = adev->gmc.fb_start; - hw_params.soc_fb_info.fb_offset = adev->vm_manager.vram_base_offset; - - /* backdoor load firmware and trigger dmub running */ - if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) - hw_params.load_inst_const = true; - - if (dmcu) - hw_params.psp_version = dmcu->psp_version; - - for (i = 0; i < fb_info->num_fb; ++i) - hw_params.fb[i] = &fb_info->fb[i]; - - /* Enable usb4 dpia in the FW APU */ - if (dc->caps.is_apu && - dc->res_pool->usb4_dpia_count != 0 && - !dc->debug.dpia_debug.bits.disable_dpia) { - hw_params.dpia_supported = true; - hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia; - hw_params.dpia_hpd_int_enable_supported = false; - hw_params.enable_non_transparent_setconfig = dc->config.consolidated_dpia_dp_lt; - hw_params.disable_dpia_bw_allocation = !dc->config.usb4_bw_alloc_support; - } - - switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(3, 5, 0): - case IP_VERSION(3, 5, 1): - case IP_VERSION(3, 6, 0): - case IP_VERSION(4, 2, 0): - case IP_VERSION(4, 2, 1): - hw_params.ips_sequential_ono = adev->external_rev_id > 0x10; - hw_params.lower_hbr3_phy_ssc = true; - break; - default: - break; - } - - status = dmub_srv_hw_init(dmub_srv, &hw_params); - if (status != DMUB_STATUS_OK) { - drm_err(adev_to_drm(adev), "Error initializing DMUB HW: %d\n", status); - return -EINVAL; - } - - /* Wait for firmware load to finish. */ - status = dmub_srv_wait_for_auto_load(dmub_srv, 100000); - if (status != DMUB_STATUS_OK) - drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status); - - /* Init DMCU and ABM if available. */ - if (dmcu && abm) { - dmcu->funcs->dmcu_init(dmcu); - abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); - } - - if (!adev->dm.dc->ctx->dmub_srv) - adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv); - if (!adev->dm.dc->ctx->dmub_srv) { - drm_err(adev_to_drm(adev), "Couldn't allocate DC DMUB server!\n"); - return -ENOMEM; - } - - drm_info(adev_to_drm(adev), "DMUB hardware initialized: version=0x%08X\n", - adev->dm.dmcub_fw_version); - - /* Keeping sanity checks off if - * DCN31 >= 4.0.59.0 - * DCN314 >= 8.0.16.0 - * Otherwise, turn on sanity checks - */ - switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(3, 1, 2): - case IP_VERSION(3, 1, 3): - if (adev->dm.dmcub_fw_version && - adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) && - adev->dm.dmcub_fw_version < DMUB_FW_VERSION(4, 0, 59)) - adev->dm.dc->debug.sanity_checks = true; - break; - case IP_VERSION(3, 1, 4): - if (adev->dm.dmcub_fw_version && - adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) && - adev->dm.dmcub_fw_version < DMUB_FW_VERSION(8, 0, 16)) - adev->dm.dc->debug.sanity_checks = true; - break; - default: - break; - } - - return 0; -} - -static void dm_dmub_hw_resume(struct amdgpu_device *adev) -{ - struct dmub_srv *dmub_srv = adev->dm.dmub_srv; - enum dmub_status status; - bool init; - int r; - - if (!dmub_srv) { - /* DMUB isn't supported on the ASIC. */ - return; - } - - status = dmub_srv_is_hw_init(dmub_srv, &init); - if (status != DMUB_STATUS_OK) - drm_warn(adev_to_drm(adev), "DMUB hardware init check failed: %d\n", status); - - if (status == DMUB_STATUS_OK && init) { - /* Wait for firmware load to finish. */ - status = dmub_srv_wait_for_auto_load(dmub_srv, 100000); - if (status != DMUB_STATUS_OK) - drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status); - } else { - /* Perform the full hardware initialization. */ - r = dm_dmub_hw_init(adev); - if (r) - drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r); - } -} - static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config) { u64 pt_base; @@ -1545,151 +404,6 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ } -static void force_connector_state( - struct amdgpu_dm_connector *aconnector, - enum drm_connector_force force_state) -{ - struct drm_connector *connector = &aconnector->base; - - mutex_lock(&connector->dev->mode_config.mutex); - aconnector->base.force = force_state; - mutex_unlock(&connector->dev->mode_config.mutex); - - mutex_lock(&aconnector->hpd_lock); - drm_kms_helper_connector_hotplug_event(connector); - mutex_unlock(&aconnector->hpd_lock); -} - -static void dm_handle_hpd_rx_offload_work(struct work_struct *work) -{ - struct hpd_rx_irq_offload_work *offload_work; - struct amdgpu_dm_connector *aconnector; - struct dc_link *dc_link; - struct amdgpu_device *adev; - enum dc_connection_type new_connection_type = dc_connection_none; - unsigned long flags; - union test_response test_response; - - memset(&test_response, 0, sizeof(test_response)); - - offload_work = container_of(work, struct hpd_rx_irq_offload_work, work); - aconnector = offload_work->offload_wq->aconnector; - adev = offload_work->adev; - - if (!aconnector) { - drm_err(adev_to_drm(adev), "Can't retrieve aconnector in hpd_rx_irq_offload_work"); - goto skip; - } - - dc_link = aconnector->dc_link; - - mutex_lock(&aconnector->hpd_lock); - if (!dc_link_detect_connection_type(dc_link, &new_connection_type)) - drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); - mutex_unlock(&aconnector->hpd_lock); - - if (new_connection_type == dc_connection_none) - goto skip; - - if (amdgpu_in_reset(adev)) - goto skip; - - if (offload_work->data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY || - offload_work->data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) { - dm_handle_mst_sideband_msg_ready_event(&aconnector->mst_mgr, DOWN_OR_UP_MSG_RDY_EVENT); - spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags); - offload_work->offload_wq->is_handling_mst_msg_rdy_event = false; - spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags); - goto skip; - } - - mutex_lock(&adev->dm.dc_lock); - if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) { - dc_link_dp_handle_automated_test(dc_link); - - if (aconnector->timing_changed) { - /* force connector disconnect and reconnect */ - force_connector_state(aconnector, DRM_FORCE_OFF); - msleep(100); - force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED); - } - - test_response.bits.ACK = 1; - - core_link_write_dpcd( - dc_link, - DP_TEST_RESPONSE, - &test_response.raw, - sizeof(test_response)); - } else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) && - dc_link_check_link_loss_status(dc_link, &offload_work->data) && - dc_link_dp_allow_hpd_rx_irq(dc_link)) { - /* offload_work->data is from handle_hpd_rx_irq-> - * schedule_hpd_rx_offload_work.this is defer handle - * for hpd short pulse. upon here, link status may be - * changed, need get latest link status from dpcd - * registers. if link status is good, skip run link - * training again. - */ - union hpd_irq_data irq_data; - - memset(&irq_data, 0, sizeof(irq_data)); - - /* before dc_link_dp_handle_link_loss, allow new link lost handle - * request be added to work queue if link lost at end of dc_link_ - * dp_handle_link_loss - */ - spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags); - offload_work->offload_wq->is_handling_link_loss = false; - spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags); - - if ((dc_link_dp_read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) && - dc_link_check_link_loss_status(dc_link, &irq_data)) - dc_link_dp_handle_link_loss(dc_link); - } - mutex_unlock(&adev->dm.dc_lock); - -skip: - kfree(offload_work); - -} - -static struct hpd_rx_irq_offload_work_queue *hpd_rx_irq_create_workqueue(struct amdgpu_device *adev) -{ - struct dc *dc = adev->dm.dc; - int max_caps = dc->caps.max_links; - int i = 0; - struct hpd_rx_irq_offload_work_queue *hpd_rx_offload_wq = NULL; - - hpd_rx_offload_wq = kzalloc_objs(*hpd_rx_offload_wq, max_caps); - - if (!hpd_rx_offload_wq) - return NULL; - - - for (i = 0; i < max_caps; i++) { - hpd_rx_offload_wq[i].wq = - create_singlethread_workqueue("amdgpu_dm_hpd_rx_offload_wq"); - - if (hpd_rx_offload_wq[i].wq == NULL) { - drm_err(adev_to_drm(adev), "create amdgpu_dm_hpd_rx_offload_wq fail!"); - goto out_err; - } - - spin_lock_init(&hpd_rx_offload_wq[i].offload_lock); - } - - return hpd_rx_offload_wq; - -out_err: - for (i = 0; i < max_caps; i++) { - if (hpd_rx_offload_wq[i].wq) - destroy_workqueue(hpd_rx_offload_wq[i].wq); - } - kfree(hpd_rx_offload_wq); - return NULL; -} - struct amdgpu_stutter_quirk { u16 chip_vendor; u16 chip_device; @@ -1775,119 +489,6 @@ dm_free_gpu_mem( } -static enum dmub_status -dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev, - enum dmub_gpint_command command_code, - uint16_t param, - uint32_t timeout_us) -{ - union dmub_gpint_data_register reg, test; - uint32_t i; - - /* Assume that VBIOS DMUB is ready to take commands */ - - reg.bits.status = 1; - reg.bits.command_code = command_code; - reg.bits.param = param; - - cgs_write_register(adev->dm.cgs_device, 0x34c0 + 0x01f8, reg.all); - - for (i = 0; i < timeout_us; ++i) { - udelay(1); - - /* Check if our GPINT got acked */ - reg.bits.status = 0; - test = (union dmub_gpint_data_register) - cgs_read_register(adev->dm.cgs_device, 0x34c0 + 0x01f8); - - if (test.all == reg.all) - return DMUB_STATUS_OK; - } - - return DMUB_STATUS_TIMEOUT; -} - -static void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev) -{ - void *bb; - long long addr; - unsigned int bb_size; - int i = 0; - uint16_t chunk; - enum dmub_gpint_command send_addrs[] = { - DMUB_GPINT__SET_BB_ADDR_WORD0, - DMUB_GPINT__SET_BB_ADDR_WORD1, - DMUB_GPINT__SET_BB_ADDR_WORD2, - DMUB_GPINT__SET_BB_ADDR_WORD3, - }; - enum dmub_status ret; - - switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(4, 0, 1): - bb_size = sizeof(struct dml2_soc_bb); - break; - case IP_VERSION(4, 2, 0): - case IP_VERSION(4, 2, 1): - bb_size = sizeof(struct dml2_soc_bb); - break; - default: - return NULL; - } - - bb = dm_allocate_gpu_mem(adev, - DC_MEM_ALLOC_TYPE_GART, - bb_size, - &addr); - if (!bb) - return NULL; - - for (i = 0; i < 4; i++) { - /* Extract 16-bit chunk */ - chunk = ((uint64_t) addr >> (i * 16)) & 0xFFFF; - /* Send the chunk */ - ret = dm_dmub_send_vbios_gpint_command(adev, send_addrs[i], chunk, 30000); - if (ret != DMUB_STATUS_OK) - goto free_bb; - } - - /* Now ask DMUB to copy the bb */ - ret = dm_dmub_send_vbios_gpint_command(adev, DMUB_GPINT__BB_COPY, 1, 200000); - if (ret != DMUB_STATUS_OK) - goto free_bb; - - return bb; - -free_bb: - dm_free_gpu_mem(adev, DC_MEM_ALLOC_TYPE_GART, (void *) bb); - return NULL; - -} - -static enum dmub_ips_disable_type dm_get_default_ips_mode( - struct amdgpu_device *adev) -{ - enum dmub_ips_disable_type ret = DMUB_IPS_ENABLE; - - switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(3, 5, 0): - case IP_VERSION(3, 6, 0): - case IP_VERSION(3, 5, 1): - ret = DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF; - break; - case IP_VERSION(4, 2, 0): - case IP_VERSION(4, 2, 1): - ret = DMUB_IPS_ENABLE; - break; - default: - /* ASICs older than DCN35 do not have IPSs */ - if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 5, 0)) - ret = DMUB_IPS_DISABLE_ALL; - break; - } - - return ret; -} - static int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm) { struct mod_power_init_params init_data[MAX_NUM_EDP]; @@ -1952,40 +553,6 @@ static int amdgpu_dm_init_power_module(struct amdgpu_display_manager *dm) return 0; } -static void hdmi_frl_status_polling_work(struct work_struct *work) -{ - struct amdgpu_display_manager *dm = - container_of(to_delayed_work(work), struct amdgpu_display_manager, - hdmi_frl_status_polling_work); - struct dc *dc = dm->dc; - struct dc_link *dc_link; - bool link_update = false; - - for (int i = 0; i < MAX_LINKS; i++) { - dc_link = dc->links[i]; - - if (!dc_link || !dc_link->local_sink) - continue; - - if (!dc_is_hdmi_signal(dc_link->connector_signal)) - continue; - - if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL) - continue; - - link_update = dc_link_frl_poll_status_flag(dc_link); - if (link_update) { - mutex_lock(&dm->dc_lock); - dc_link_detect(dc_link, DETECT_REASON_RETRAIN); - mutex_unlock(&dm->dc_lock); - } - } - - queue_delayed_work(dm->hdmi_frl_status_polling_wq, - &dm->hdmi_frl_status_polling_work, - msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms)); -} - static int amdgpu_dm_init(struct amdgpu_device *adev) { struct dc_init_data init_data; @@ -2212,7 +779,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) dc_hardware_init(adev->dm.dc); - adev->dm.hpd_rx_offload_wq = hpd_rx_irq_create_workqueue(adev); + adev->dm.hpd_rx_offload_wq = amdgpu_dm_hpd_rx_irq_create_workqueue(adev); if (!adev->dm.hpd_rx_offload_wq) { drm_err(adev_to_drm(adev), "failed to create hpd rx offload workqueue.\n"); goto error; @@ -2265,8 +832,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) create_singlethread_workqueue("hdmi_frl_status_polling_workqueue"); if (!adev->dm.hdmi_frl_status_polling_wq) drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_workqueue\n"); - adev->dm.hdmi_frl_status_polling_delay_ms = 200; - INIT_DELAYED_WORK(&adev->dm.hdmi_frl_status_polling_work, hdmi_frl_status_polling_work); } if (dc_is_dmub_outbox_supported(adev->dm.dc)) { init_completion(&adev->dm.dmub_aux_transfer_done); @@ -2283,8 +848,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) } amdgpu_dm_outbox_init(adev); - if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY, - dmub_aux_setconfig_callback, false)) { + if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY, + dm_dmub_aux_setconfig_callback, false)) { drm_err(adev_to_drm(adev), "fail to register dmub aux callback"); goto error; } @@ -2292,16 +857,17 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) for (size_t i = 0; i < ARRAY_SIZE(adev->dm.fused_io); i++) init_completion(&adev->dm.fused_io[i].replied); - if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_FUSED_IO, - dmub_aux_fused_io_callback, false)) { + if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_FUSED_IO, + dm_dmub_aux_fused_io_callback, false)) { drm_err(adev_to_drm(adev), "fail to register dmub fused io callback"); goto error; } /* Enable outbox notification only after IRQ handlers are registered and DMUB is alive. * It is expected that DMUB will resend any pending notifications at this point. Note - * that hpd and hpd_irq handler registration are deferred to register_hpd_handlers() to - * align legacy interface initialization sequence. Connection status will be proactivly - * detected once in the amdgpu_dm_initialize_drm_device. + * that hpd and hpd_irq handler registration are deferred to + * amdgpu_dm_register_hpd_handlers() to align legacy interface initialization + * sequence. Connection status will be proactivly detected once in the + * amdgpu_dm_initialize_drm_device. */ dc_enable_dmub_outbox(adev->dm.dc); @@ -2581,224 +1147,6 @@ static int load_dmcu_fw(struct amdgpu_device *adev) return 0; } -static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address) -{ - struct amdgpu_device *adev = ctx; - - return dm_read_reg(adev->dm.dc->ctx, address); -} - -static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address, - uint32_t value) -{ - struct amdgpu_device *adev = ctx; - - return dm_write_reg(adev->dm.dc->ctx, address, value); -} - -static int dm_dmub_sw_init(struct amdgpu_device *adev) -{ - struct dmub_srv_create_params create_params; - struct dmub_srv_fw_meta_info_params fw_meta_info_params; - struct dmub_srv_region_params region_params; - struct dmub_srv_region_info region_info; - struct dmub_srv_memory_params memory_params; - struct dmub_fw_meta_info fw_info; - struct dmub_srv_fb_info *fb_info; - struct dmub_srv *dmub_srv; - const struct dmcub_firmware_header_v1_0 *hdr; - enum dmub_asic dmub_asic; - enum dmub_status status; - static enum dmub_window_memory_type window_memory_type[DMUB_WINDOW_TOTAL] = { - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_0_INST_CONST - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_1_STACK - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_2_BSS_DATA - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_3_VBIOS - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_4_MAILBOX - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_5_TRACEBUFF - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_6_FW_STATE - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_7_SCRATCH_MEM - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_IB_MEM - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_SHARED_STATE - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_LSDMA_BUFFER - DMUB_WINDOW_MEMORY_TYPE_FB, //DMUB_WINDOW_CURSOR_OFFLOAD - }; - int r; - - switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(2, 1, 0): - dmub_asic = DMUB_ASIC_DCN21; - break; - case IP_VERSION(3, 0, 0): - dmub_asic = DMUB_ASIC_DCN30; - break; - case IP_VERSION(3, 0, 1): - dmub_asic = DMUB_ASIC_DCN301; - break; - case IP_VERSION(3, 0, 2): - dmub_asic = DMUB_ASIC_DCN302; - break; - case IP_VERSION(3, 0, 3): - dmub_asic = DMUB_ASIC_DCN303; - break; - case IP_VERSION(3, 1, 2): - case IP_VERSION(3, 1, 3): - dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31; - break; - case IP_VERSION(3, 1, 4): - dmub_asic = DMUB_ASIC_DCN314; - break; - case IP_VERSION(3, 1, 5): - dmub_asic = DMUB_ASIC_DCN315; - break; - case IP_VERSION(3, 1, 6): - dmub_asic = DMUB_ASIC_DCN316; - break; - case IP_VERSION(3, 2, 0): - dmub_asic = DMUB_ASIC_DCN32; - break; - case IP_VERSION(3, 2, 1): - dmub_asic = DMUB_ASIC_DCN321; - break; - case IP_VERSION(3, 5, 0): - case IP_VERSION(3, 5, 1): - dmub_asic = DMUB_ASIC_DCN35; - break; - case IP_VERSION(3, 6, 0): - dmub_asic = DMUB_ASIC_DCN36; - break; - case IP_VERSION(4, 0, 1): - dmub_asic = DMUB_ASIC_DCN401; - break; - case IP_VERSION(4, 2, 0): - dmub_asic = DMUB_ASIC_DCN42; - break; - case IP_VERSION(4, 2, 1): - dmub_asic = DMUB_ASIC_DCN42B; - break; - default: - /* ASIC doesn't support DMUB. */ - return 0; - } - - hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data; - adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version); - - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].ucode_id = - AMDGPU_UCODE_ID_DMCUB; - adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].fw = - adev->dm.dmub_fw; - adev->firmware.fw_size += - ALIGN(le32_to_cpu(hdr->inst_const_bytes), PAGE_SIZE); - - drm_info(adev_to_drm(adev), "Loading DMUB firmware via PSP: version=0x%08X\n", - adev->dm.dmcub_fw_version); - } - - - adev->dm.dmub_srv = kzalloc_obj(*adev->dm.dmub_srv); - dmub_srv = adev->dm.dmub_srv; - - if (!dmub_srv) { - drm_err(adev_to_drm(adev), "Failed to allocate DMUB service!\n"); - return -ENOMEM; - } - - memset(&create_params, 0, sizeof(create_params)); - create_params.user_ctx = adev; - create_params.funcs.reg_read = amdgpu_dm_dmub_reg_read; - create_params.funcs.reg_write = amdgpu_dm_dmub_reg_write; - create_params.asic = dmub_asic; - - /* Create the DMUB service. */ - status = dmub_srv_create(dmub_srv, &create_params); - if (status != DMUB_STATUS_OK) { - drm_err(adev_to_drm(adev), "Error creating DMUB service: %d\n", status); - return -EINVAL; - } - - /* Extract the FW meta info. */ - memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params)); - - fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - - PSP_HEADER_BYTES_256; - fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); - fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - PSP_HEADER_BYTES_256; - fw_meta_info_params.fw_bss_data = fw_meta_info_params.bss_data_size ? adev->dm.dmub_fw->data + - le32_to_cpu(hdr->header.ucode_array_offset_bytes) + - le32_to_cpu(hdr->inst_const_bytes) : NULL; - fw_meta_info_params.custom_psp_footer_size = 0; - - status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info); - if (status != DMUB_STATUS_OK) { - /* Skip returning early, just log the error. */ - drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status); - // return -EINVAL; - } - - /* Calculate the size of all the regions for the DMUB service. */ - memset(®ion_params, 0, sizeof(region_params)); - - region_params.inst_const_size = fw_meta_info_params.inst_const_size; - region_params.bss_data_size = fw_meta_info_params.bss_data_size; - region_params.vbios_size = adev->bios_size; - region_params.fw_bss_data = fw_meta_info_params.fw_bss_data; - region_params.fw_inst_const = fw_meta_info_params.fw_inst_const; - region_params.window_memory_type = window_memory_type; - region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL; - - status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, - ®ion_info); - - if (status != DMUB_STATUS_OK) { - drm_err(adev_to_drm(adev), "Error calculating DMUB region info: %d\n", status); - return -EINVAL; - } - - /* - * Allocate a framebuffer based on the total size of all the regions. - * TODO: Move this into GART. - */ - r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE, - AMDGPU_GEM_DOMAIN_VRAM | - AMDGPU_GEM_DOMAIN_GTT, - &adev->dm.dmub_bo, - &adev->dm.dmub_bo_gpu_addr, - &adev->dm.dmub_bo_cpu_addr); - if (r) - return r; - - /* Rebase the regions on the framebuffer address. */ - memset(&memory_params, 0, sizeof(memory_params)); - memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr; - memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr; - memory_params.region_info = ®ion_info; - memory_params.window_memory_type = window_memory_type; - - adev->dm.dmub_fb_info = kzalloc_obj(*adev->dm.dmub_fb_info); - fb_info = adev->dm.dmub_fb_info; - - if (!fb_info) { - drm_err(adev_to_drm(adev), - "Failed to allocate framebuffer info for DMUB service!\n"); - return -ENOMEM; - } - - status = dmub_srv_calc_mem_info(dmub_srv, &memory_params, fb_info); - if (status != DMUB_STATUS_OK) { - drm_err(adev_to_drm(adev), "Error calculating DMUB FB info: %d\n", status); - return -EINVAL; - } - - adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev); - adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size; - - return 0; -} - static int dm_sw_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -2852,41 +1200,6 @@ static int dm_sw_fini(struct amdgpu_ip_block *ip_block) return 0; } -static int detect_mst_link_for_all_connectors(struct drm_device *dev) -{ - struct amdgpu_dm_connector *aconnector; - struct drm_connector *connector; - struct drm_connector_list_iter iter; - int ret = 0; - - drm_connector_list_iter_begin(dev, &iter); - drm_for_each_connector_iter(connector, &iter) { - - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - continue; - - aconnector = to_amdgpu_dm_connector(connector); - if (aconnector->dc_link->type == dc_connection_mst_branch && - aconnector->mst_mgr.aux) { - drm_dbg_kms(dev, "DM_MST: starting TM on aconnector: %p [id: %d]\n", - aconnector, - aconnector->base.base.id); - - ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true); - if (ret < 0) { - drm_err(dev, "DM_MST: Failed to start MST\n"); - aconnector->dc_link->type = - dc_connection_single; - ret = dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx, - aconnector->dc_link); - break; - } - } - } - drm_connector_list_iter_end(&iter); - - return ret; -} static void amdgpu_dm_boot_time_crc_init(struct amdgpu_device *adev) { @@ -2984,7 +1297,7 @@ static int dm_late_init(struct amdgpu_ip_block *ip_block) } } - return detect_mst_link_for_all_connectors(adev_to_drm(adev)); + return amdgpu_dm_detect_mst_link_for_all_connectors(adev_to_drm(adev)); } static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr) @@ -3038,48 +1351,6 @@ static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr) mutex_unlock(&mgr->lock); } -void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector) -{ - struct cec_notifier *n = aconnector->notifier; - - if (!n) - return; - - cec_notifier_phys_addr_invalidate(n); -} - -void hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector) -{ - struct drm_connector *connector = &aconnector->base; - struct cec_notifier *n = aconnector->notifier; - - if (!n) - return; - - cec_notifier_set_phys_addr(n, - connector->display_info.source_physical_address); -} - -static void s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend) -{ - struct amdgpu_dm_connector *aconnector; - struct drm_connector *connector; - struct drm_connector_list_iter conn_iter; - - drm_connector_list_iter_begin(ddev, &conn_iter); - drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - continue; - - aconnector = to_amdgpu_dm_connector(connector); - if (suspend) - hdmi_cec_unset_edid(aconnector); - else - hdmi_cec_set_edid(aconnector); - } - drm_connector_list_iter_end(&conn_iter); -} - static void s3_handle_mst(struct drm_device *dev, bool suspend) { struct amdgpu_dm_connector *aconnector; @@ -3182,7 +1453,7 @@ static int dm_oem_i2c_hw_init(struct amdgpu_device *adev) oem_ddc_service = dc_get_oem_i2c_device(adev->dm.dc); if (oem_ddc_service) { - oem_i2c = create_i2c(oem_ddc_service, true); + oem_i2c = amdgpu_dm_create_i2c(oem_ddc_service, true); if (!oem_i2c) { drm_info(adev_to_drm(adev), "Failed to create oem i2c adapter data\n"); return -ENOMEM; @@ -3267,7 +1538,7 @@ static void dm_gpureset_toggle_interrupts(struct amdgpu_device *adev, int i = 0; for (i = 0; i < state->stream_count; i++) { - acrtc = get_crtc_by_otg_inst( + acrtc = amdgpu_dm_get_crtc_by_otg_inst( adev, state->stream_status[i].primary_otg_inst); if (acrtc && state->stream_status[i].plane_count != 0) { @@ -3344,16 +1615,6 @@ static enum dc_status amdgpu_dm_commit_zero_streams(struct dc *dc) return dc_commit_streams(dc, ¶ms); } -static void hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm) -{ - int i; - - if (dm->hpd_rx_offload_wq) { - for (i = 0; i < dm->dc->caps.max_links; i++) - flush_workqueue(dm->hpd_rx_offload_wq[i].wq); - } -} - static int dm_cache_state(struct amdgpu_device *adev) { int r; @@ -3449,7 +1710,7 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block) amdgpu_dm_irq_suspend(adev); - hpd_rx_irq_work_suspend(dm); + amdgpu_dm_hpd_rx_irq_work_suspend(dm); return 0; } @@ -3461,7 +1722,7 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block) return r; } - s3_handle_hdmi_cec(adev_to_drm(adev), true); + amdgpu_dm_s3_handle_hdmi_cec(adev_to_drm(adev), true); s3_handle_mst(adev_to_drm(adev), true); @@ -3475,7 +1736,7 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block) scoped_guard(mutex, &dm->dc_lock) amdgpu_dm_ism_force_full_power(dm); - hpd_rx_irq_work_suspend(dm); + amdgpu_dm_hpd_rx_irq_work_suspend(dm); dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3); @@ -3487,26 +1748,7 @@ static int dm_suspend(struct amdgpu_ip_block *ip_block) return 0; } -struct drm_connector * -amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_commit *state, - struct drm_crtc *crtc) -{ - u32 i; - struct drm_connector_state *new_con_state; - struct drm_connector *connector; - struct drm_crtc *crtc_from_state; - - for_each_new_connector_in_state(state, connector, new_con_state, i) { - crtc_from_state = new_con_state->crtc; - - if (crtc_from_state == crtc) - return connector; - } - - return NULL; -} - -static void emulated_link_detect(struct dc_link *link) +void amdgpu_dm_emulated_link_detect(struct dc_link *link) { struct dc_sink_init_data sink_init_data = { 0 }; struct display_sink_capability sink_caps = { 0 }; @@ -3627,8 +1869,8 @@ static void dm_gpureset_commit_state(struct dc_state *dc_state, } } -static void apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev, - struct dc_sink *sink) +void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev, + struct dc_sink *sink) { struct dc_panel_patch *ppatch = NULL; @@ -3771,8 +2013,7 @@ static int dm_resume(struct amdgpu_ip_block *ip_block) for (i = 0; i < dc_state->stream_count; i++) { dc_state->streams[i]->mode_changed = true; for (j = 0; j < dc_state->stream_status[i].plane_count; j++) { - dc_state->stream_status[i].plane_states[j]->update_flags.raw - = 0xffffffff; + dc_pipe_update_bits_set_full(&dc_state->stream_status[i].plane_states[j]->update_bits); } } @@ -3835,7 +2076,7 @@ static int dm_resume(struct amdgpu_ip_block *ip_block) */ amdgpu_dm_irq_resume_early(adev); - s3_handle_hdmi_cec(ddev, false); + amdgpu_dm_s3_handle_hdmi_cec(ddev, false); /* On resume we need to rewrite the MSTM control bits to enable MST*/ s3_handle_mst(ddev, false); @@ -3870,14 +2111,14 @@ static int dm_resume(struct amdgpu_ip_block *ip_block) drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); if (aconnector->base.force && new_connection_type == dc_connection_none) { - emulated_link_detect(aconnector->dc_link); + amdgpu_dm_emulated_link_detect(aconnector->dc_link); } else { guard(mutex)(&dm->dc_lock); dc_exit_ips_for_hw_access(dm->dc); ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_RESUMEFROMS3S4); if (ret) { /* w/a delay for certain panels */ - apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink); + amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink); } } @@ -3955,7 +2196,6 @@ static const struct amd_ip_funcs amdgpu_dm_funcs = { .resume = dm_resume, .is_idle = dm_is_idle, .wait_for_idle = dm_wait_for_idle, - .check_soft_reset = dm_check_soft_reset, .soft_reset = dm_soft_reset, .set_clockgating_state = dm_set_clockgating_state, .set_powergating_state = dm_set_powergating_state, @@ -3988,1070 +2228,6 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = { .atomic_commit_setup = amdgpu_dm_atomic_setup_commit, }; -#define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C - -static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector) -{ - struct drm_connector *connector = &aconnector->base; - struct drm_display_info *display_info = &connector->display_info; - struct dc_link *link = aconnector->dc_link; - struct amdgpu_device *adev; - - adev = drm_to_adev(connector->dev); - - link->panel_type = PANEL_TYPE_NONE; - - switch (display_info->amd_vsdb.panel_type) { - case AMD_VSDB_PANEL_TYPE_OLED: - link->panel_type = PANEL_TYPE_OLED; - break; - case AMD_VSDB_PANEL_TYPE_MINILED: - link->panel_type = PANEL_TYPE_MINILED; - break; - } - - /* If VSDB didn't determine panel type, check DPCD ext caps */ - if (link->panel_type == PANEL_TYPE_NONE) { - if (link->dpcd_sink_ext_caps.bits.miniled == 1) - link->panel_type = PANEL_TYPE_MINILED; - if (link->dpcd_sink_ext_caps.bits.oled == 1) - link->panel_type = PANEL_TYPE_OLED; - } - - /* If VSDB and DPCD didn't determine panel type, check DID */ - if (link->panel_type == PANEL_TYPE_NONE) { - if (display_info->panel_type == DRM_MODE_PANEL_TYPE_LCD) - link->panel_type = PANEL_TYPE_LCD; - else if (display_info->panel_type == DRM_MODE_PANEL_TYPE_OLED) - link->panel_type = PANEL_TYPE_OLED; - } - - if (link->panel_type == PANEL_TYPE_NONE) { - struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb; - u32 lum1_max = vsdb->luminance_range1.max_luminance; - u32 lum2_max = vsdb->luminance_range2.max_luminance; - - if (vsdb->version && link->local_sink && - link->local_sink->edid_caps.manufacturer_id == - DDC_MANUFACTURERNAME_SAMSUNG && - lum1_max >= ((lum2_max * 3) / 2)) - link->panel_type = PANEL_TYPE_MINILED; - } - - if (link->panel_type == PANEL_TYPE_OLED) - drm_object_property_set_value(&connector->base, - adev_to_drm(adev)->mode_config.panel_type_property, - DRM_MODE_PANEL_TYPE_OLED); - else if (link->panel_type == PANEL_TYPE_LCD) - drm_object_property_set_value(&connector->base, - adev_to_drm(adev)->mode_config.panel_type_property, - DRM_MODE_PANEL_TYPE_LCD); - else - drm_object_property_set_value(&connector->base, - adev_to_drm(adev)->mode_config.panel_type_property, - DRM_MODE_PANEL_TYPE_UNKNOWN); - - drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type); -} - -static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) -{ - const struct drm_panel_backlight_quirk *panel_backlight_quirk; - struct amdgpu_dm_backlight_caps *caps; - struct drm_connector *conn_base; - struct amdgpu_device *adev; - struct drm_luminance_range_info *luminance_range; - struct drm_device *drm; - - if (aconnector->bl_idx == -1 || - aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP) - return; - - conn_base = &aconnector->base; - drm = conn_base->dev; - adev = drm_to_adev(drm); - - caps = &adev->dm.backlight_caps[aconnector->bl_idx]; - caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; - caps->aux_support = false; - - if (caps->ext_caps->bits.oled == 1 - /* - * || - * caps->ext_caps->bits.sdr_aux_backlight_control == 1 || - * caps->ext_caps->bits.hdr_aux_backlight_control == 1 - */) - caps->aux_support = true; - - if (amdgpu_backlight == 0) - caps->aux_support = false; - else if (amdgpu_backlight == 1) - caps->aux_support = true; - if (caps->aux_support) - aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; - - luminance_range = &conn_base->display_info.luminance_range; - - if (luminance_range->max_luminance) - caps->aux_max_input_signal = luminance_range->max_luminance; - else - caps->aux_max_input_signal = 512; - - if (luminance_range->min_luminance) - caps->aux_min_input_signal = luminance_range->min_luminance; - else - caps->aux_min_input_signal = 1; - - panel_backlight_quirk = - drm_get_panel_backlight_quirk(aconnector->drm_edid); - if (!IS_ERR_OR_NULL(panel_backlight_quirk)) { - if (panel_backlight_quirk->min_brightness) { - caps->min_input_signal = - panel_backlight_quirk->min_brightness - 1; - drm_info(drm, - "Applying panel backlight quirk, min_brightness: %d\n", - caps->min_input_signal); - } - if (panel_backlight_quirk->brightness_mask) { - drm_info(drm, - "Applying panel backlight quirk, brightness_mask: 0x%X\n", - panel_backlight_quirk->brightness_mask); - caps->brightness_mask = - panel_backlight_quirk->brightness_mask; - } - } -} - -DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T)) - -void amdgpu_dm_update_connector_after_detect( - struct amdgpu_dm_connector *aconnector) -{ - struct drm_connector *connector = &aconnector->base; - struct dc_sink *sink __free(sink_release) = NULL; - struct drm_device *dev = connector->dev; - - /* MST handled by drm_mst framework */ - if (aconnector->mst_mgr.mst_state == true) - return; - - sink = aconnector->dc_link->local_sink; - if (sink) - dc_sink_retain(sink); - - /* - * Edid mgmt connector gets first update only in mode_valid hook and then - * the connector sink is set to either fake or physical sink depends on link status. - * Skip if already done during boot. - */ - if (aconnector->base.force != DRM_FORCE_UNSPECIFIED - && aconnector->dc_em_sink) { - - /* - * For S3 resume with headless use eml_sink to fake stream - * because on resume connector->sink is set to NULL - */ - guard(mutex)(&dev->mode_config.mutex); - - if (sink) { - if (aconnector->dc_sink) { - amdgpu_dm_update_freesync_caps(connector, NULL, true); - /* - * retain and release below are used to - * bump up refcount for sink because the link doesn't point - * to it anymore after disconnect, so on next crtc to connector - * reshuffle by UMD we will get into unwanted dc_sink release - */ - dc_sink_release(aconnector->dc_sink); - } - aconnector->dc_sink = sink; - dc_sink_retain(aconnector->dc_sink); - amdgpu_dm_update_freesync_caps(connector, - aconnector->drm_edid, true); - } else { - amdgpu_dm_update_freesync_caps(connector, NULL, true); - if (!aconnector->dc_sink) { - aconnector->dc_sink = aconnector->dc_em_sink; - dc_sink_retain(aconnector->dc_sink); - } - } - - return; - } - - /* - * TODO: temporary guard to look for proper fix - * if this sink is MST sink, we should not do anything - */ - if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) - return; - - if (aconnector->dc_sink == sink) { - /* - * We got a DP short pulse (Link Loss, DP CTS, etc...). - * Do nothing!! - */ - drm_dbg_kms(dev, "DCHPD: connector_id=%d: dc_sink didn't change.\n", - aconnector->connector_id); - return; - } - - drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n", - aconnector->connector_id, aconnector->dc_sink, sink); - - /* When polling, DRM has already locked the mutex for us. */ - if (!drm_kms_helper_is_poll_worker()) - mutex_lock(&dev->mode_config.mutex); - - /* - * 1. Update status of the drm connector - * 2. Send an event and let userspace tell us what to do - */ - if (sink) { - /* - * TODO: check if we still need the S3 mode update workaround. - * If yes, put it here. - */ - if (aconnector->dc_sink) { - amdgpu_dm_update_freesync_caps(connector, NULL, true); - dc_sink_release(aconnector->dc_sink); - } - - aconnector->dc_sink = sink; - dc_sink_retain(aconnector->dc_sink); - drm_edid_free(aconnector->drm_edid); - aconnector->drm_edid = NULL; - if (sink->dc_edid.length == 0) { - hdmi_cec_unset_edid(aconnector); - if (aconnector->dc_link->aux_mode) { - drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); - } - } else { - const struct edid *edid = (const struct edid *)sink->dc_edid.raw_edid; - - aconnector->drm_edid = drm_edid_alloc(edid, sink->dc_edid.length); - drm_edid_connector_update(connector, aconnector->drm_edid); - - hdmi_cec_set_edid(aconnector); - if (aconnector->dc_link->aux_mode) - drm_dp_cec_attach(&aconnector->dm_dp_aux.aux, - connector->display_info.source_physical_address); - } - - if (!aconnector->timing_requested) { - aconnector->timing_requested = - kzalloc_obj(struct dc_crtc_timing); - if (!aconnector->timing_requested) - drm_err(dev, - "failed to create aconnector->requested_timing\n"); - } - - amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid, true); - update_connector_ext_caps(aconnector); - dm_set_panel_type(aconnector); - } else { - hdmi_cec_unset_edid(aconnector); - drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); - amdgpu_dm_update_freesync_caps(connector, NULL, true); - aconnector->num_modes = 0; - dc_sink_release(aconnector->dc_sink); - aconnector->dc_sink = NULL; - drm_edid_free(aconnector->drm_edid); - aconnector->drm_edid = NULL; - kfree(aconnector->timing_requested); - aconnector->timing_requested = NULL; - /* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */ - if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) - connector->state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; - } - - update_subconnector_property(aconnector); - - /* When polling, the mutex will be unlocked for us by DRM. */ - if (!drm_kms_helper_is_poll_worker()) - mutex_unlock(&dev->mode_config.mutex); -} - -static bool are_sinks_equal(const struct dc_sink *sink1, const struct dc_sink *sink2) -{ - if (!sink1 || !sink2) - return false; - if (sink1->sink_signal != sink2->sink_signal) - return false; - - if (sink1->dc_edid.length != sink2->dc_edid.length) - return false; - - if (memcmp(sink1->dc_edid.raw_edid, sink2->dc_edid.raw_edid, - sink1->dc_edid.length) != 0) - return false; - return true; -} - - -/** - * DOC: hdmi_hpd_debounce_work - * - * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD - * (such as during power save transitions), this delay determines how long to - * wait before processing the HPD event. This allows distinguishing between a - * physical unplug (>hdmi_hpd_debounce_delay) - * and a spontaneous RX HPD toggle (base; - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); - struct dc *dc = aconnector->dc_link->ctx->dc; - bool fake_reconnect = false; - bool reallow_idle = false; - bool ret = false; - guard(mutex)(&aconnector->hpd_lock); - - /* Re-detect the display */ - scoped_guard(mutex, &adev->dm.dc_lock) { - if (dc->caps.ips_support && dc->ctx->dmub_srv->idle_allowed) { - dc_allow_idle_optimizations(dc, false); - reallow_idle = true; - } - ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD); - } - - if (ret) { - /* Apply workaround delay for certain panels */ - apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink); - /* Compare sinks to determine if this was a spontaneous HPD toggle */ - if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) { - /* - * Sinks match - this was a spontaneous HDMI HPD toggle. - */ - drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n"); - fake_reconnect = true; - } - - /* Update connector state */ - amdgpu_dm_update_connector_after_detect(aconnector); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - /* Only notify OS if sink actually changed */ - if (!fake_reconnect && aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_hotplug_event(dev); - } - - /* Release the cached sink reference */ - if (aconnector->hdmi_prev_sink) { - dc_sink_release(aconnector->hdmi_prev_sink); - aconnector->hdmi_prev_sink = NULL; - } - - scoped_guard(mutex, &adev->dm.dc_lock) { - if (reallow_idle && dc->caps.ips_support) - dc_allow_idle_optimizations(dc, true); - } -} - -static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector) -{ - struct drm_connector *connector = &aconnector->base; - struct drm_device *dev = connector->dev; - enum dc_connection_type new_connection_type = dc_connection_none; - struct amdgpu_device *adev = drm_to_adev(dev); - struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); - struct dc *dc = aconnector->dc_link->ctx->dc; - bool ret = false; - bool debounce_required = false; - - if (adev->dm.disable_hpd_irq) - return; - - /* - * In case of failure or MST no need to update connector status or notify the OS - * since (for MST case) MST does this in its own context. - */ - guard(mutex)(&aconnector->hpd_lock); - - if (adev->dm.hdcp_workqueue) { - hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index); - dm_con_state->update_hdcp = true; - } - if (aconnector->fake_enable) - aconnector->fake_enable = false; - - aconnector->timing_changed = false; - - if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type)) - drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); - - /* - * Check for HDMI disconnect with debounce enabled. - */ - debounce_required = (aconnector->hdmi_hpd_debounce_delay_ms > 0 && - dc_is_hdmi_signal(aconnector->dc_link->connector_signal) && - new_connection_type == dc_connection_none && - aconnector->dc_link->local_sink != NULL); - - if (aconnector->base.force && new_connection_type == dc_connection_none) { - emulated_link_detect(aconnector->dc_link); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_connector_hotplug_event(connector); - } else if (debounce_required) { - /* - * HDMI disconnect detected - schedule delayed work instead of - * processing immediately. This allows us to coalesce spurious - * HDMI signals from physical unplugs. - */ - drm_dbg_kms(dev, "HDMI HPD: Disconnect detected, scheduling debounce work (%u ms)\n", - aconnector->hdmi_hpd_debounce_delay_ms); - - /* Cache the current sink for later comparison */ - if (aconnector->hdmi_prev_sink) - dc_sink_release(aconnector->hdmi_prev_sink); - aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink; - if (aconnector->hdmi_prev_sink) - dc_sink_retain(aconnector->hdmi_prev_sink); - - /* Schedule delayed detection. */ - if (mod_delayed_work(system_percpu_wq, - &aconnector->hdmi_hpd_debounce_work, - msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms))) - drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n"); - - } else { - - /* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */ - if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work)) - return; - - scoped_guard(mutex, &adev->dm.dc_lock) { - dc_exit_ips_for_hw_access(dc); - ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD); - } - if (ret) { - /* w/a delay for certain panels */ - apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink); - amdgpu_dm_update_connector_after_detect(aconnector); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - if (aconnector->base.force == DRM_FORCE_UNSPECIFIED) - drm_kms_helper_connector_hotplug_event(connector); - } - } -} - -static void handle_hpd_irq(void *param) -{ - struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param; - - handle_hpd_irq_helper(aconnector); - -} - -static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_rx_irq_offload_work_queue *offload_wq, - union hpd_irq_data hpd_irq_data) -{ - struct hpd_rx_irq_offload_work *offload_work = kzalloc_obj(*offload_work); - - if (!offload_work) { - drm_err(adev_to_drm(adev), "Failed to allocate hpd_rx_irq_offload_work.\n"); - return; - } - - INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); - offload_work->data = hpd_irq_data; - offload_work->offload_wq = offload_wq; - offload_work->adev = adev; - - queue_work(offload_wq->wq, &offload_work->work); - drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work"); -} - -static void handle_hpd_rx_irq(void *param) -{ - struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param; - struct drm_connector *connector = &aconnector->base; - struct drm_device *dev = connector->dev; - struct dc_link *dc_link = aconnector->dc_link; - bool is_mst_root_connector = aconnector->mst_mgr.mst_state; - bool result = false; - enum dc_connection_type new_connection_type = dc_connection_none; - struct amdgpu_device *adev = drm_to_adev(dev); - union hpd_irq_data hpd_irq_data; - bool link_loss = false; - bool has_left_work = false; - int idx = dc_link->link_index; - struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx]; - struct dc *dc = aconnector->dc_link->ctx->dc; - - memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); - - if (adev->dm.disable_hpd_irq) - return; - - /* - * TODO:Temporary add mutex to protect hpd interrupt not have a gpio - * conflict, after implement i2c helper, this mutex should be - * retired. - */ - mutex_lock(&aconnector->hpd_lock); - - result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data, - &link_loss, true, &has_left_work); - - if (!has_left_work) - goto out; - - if (hpd_irq_data.bytes.device_service_irq.bits.AUTOMATED_TEST) { - schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data); - goto out; - } - - if (dc_link_dp_allow_hpd_rx_irq(dc_link)) { - if (hpd_irq_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY || - hpd_irq_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) { - bool skip = false; - - /* - * DOWN_REP_MSG_RDY is also handled by polling method - * mgr->cbs->poll_hpd_irq() - */ - spin_lock(&offload_wq->offload_lock); - skip = offload_wq->is_handling_mst_msg_rdy_event; - - if (!skip) - offload_wq->is_handling_mst_msg_rdy_event = true; - - spin_unlock(&offload_wq->offload_lock); - - if (!skip) - schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data); - - goto out; - } - - if (link_loss) { - bool skip = false; - - spin_lock(&offload_wq->offload_lock); - skip = offload_wq->is_handling_link_loss; - - if (!skip) - offload_wq->is_handling_link_loss = true; - - spin_unlock(&offload_wq->offload_lock); - - if (!skip) - schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data); - - goto out; - } - } - -out: - if (result && !is_mst_root_connector) { - /* Downstream Port status changed. */ - if (!dc_link_detect_connection_type(dc_link, &new_connection_type)) - drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); - - if (aconnector->base.force && new_connection_type == dc_connection_none) { - emulated_link_detect(dc_link); - - if (aconnector->fake_enable) - aconnector->fake_enable = false; - - amdgpu_dm_update_connector_after_detect(aconnector); - - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - drm_kms_helper_connector_hotplug_event(connector); - } else { - bool ret = false; - - mutex_lock(&adev->dm.dc_lock); - dc_exit_ips_for_hw_access(dc); - ret = dc_link_detect(dc_link, DETECT_REASON_HPDRX); - mutex_unlock(&adev->dm.dc_lock); - - if (ret) { - if (aconnector->fake_enable) - aconnector->fake_enable = false; - - amdgpu_dm_update_connector_after_detect(aconnector); - - drm_modeset_lock_all(dev); - dm_restore_drm_connector_state(dev, connector); - drm_modeset_unlock_all(dev); - - drm_kms_helper_connector_hotplug_event(connector); - } - } - } - if (hpd_irq_data.bytes.device_service_irq.bits.CP_IRQ) { - if (adev->dm.hdcp_workqueue) - hdcp_handle_cpirq(adev->dm.hdcp_workqueue, aconnector->base.index); - } - - if (dc_link->type != dc_connection_mst_branch) - drm_dp_cec_irq(&aconnector->dm_dp_aux.aux); - - mutex_unlock(&aconnector->hpd_lock); -} - -static int register_hpd_handlers(struct amdgpu_device *adev) -{ - struct drm_device *dev = adev_to_drm(adev); - struct drm_connector *connector; - struct amdgpu_dm_connector *aconnector; - const struct dc_link *dc_link; - struct dc_interrupt_params int_params = {0}; - - int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; - int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; - - if (dc_is_dmub_outbox_supported(adev->dm.dc)) { - if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, - dmub_hpd_callback, true)) { - drm_err(adev_to_drm(adev), "fail to register dmub hpd callback"); - return -EINVAL; - } - - if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, - dmub_hpd_callback, true)) { - drm_err(adev_to_drm(adev), "fail to register dmub hpd callback"); - return -EINVAL; - } - - if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_SENSE_NOTIFY, - dmub_hpd_sense_callback, true)) { - drm_err(adev_to_drm(adev), "fail to register dmub hpd sense callback"); - return -EINVAL; - } - } - - list_for_each_entry(connector, - &dev->mode_config.connector_list, head) { - - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - continue; - - aconnector = to_amdgpu_dm_connector(connector); - dc_link = aconnector->dc_link; - - if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) { - int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; - int_params.irq_source = dc_link->irq_source_hpd; - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_HPD1 || - int_params.irq_source > DC_IRQ_SOURCE_HPD6) { - drm_err(adev_to_drm(adev), "Failed to register hpd irq!\n"); - return -EINVAL; - } - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - handle_hpd_irq, (void *) aconnector)) - return -ENOMEM; - } - - if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) { - - /* Also register for DP short pulse (hpd_rx). */ - int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; - int_params.irq_source = dc_link->irq_source_hpd_rx; - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_HPD1RX || - int_params.irq_source > DC_IRQ_SOURCE_HPD6RX) { - drm_err(adev_to_drm(adev), "Failed to register hpd rx irq!\n"); - return -EINVAL; - } - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - handle_hpd_rx_irq, (void *) aconnector)) - return -ENOMEM; - } - } - return 0; -} - -/* Register IRQ sources and initialize IRQ callbacks */ -static int dce110_register_irq_handlers(struct amdgpu_device *adev) -{ - struct dc *dc = adev->dm.dc; - struct common_irq_params *c_irq_params; - struct dc_interrupt_params int_params = {0}; - int r; - int i; - unsigned int src_id; - unsigned int client_id = AMDGPU_IRQ_CLIENTID_LEGACY; - /* Use different interrupts for VBLANK on DCE 6 vs. newer. */ - const unsigned int vblank_d1 = - adev->dm.dc->ctx->dce_version >= DCE_VERSION_8_0 - ? VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 : 1; - - if (adev->family >= AMDGPU_FAMILY_AI) - client_id = SOC15_IH_CLIENTID_DCE; - - int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; - int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; - - /* - * Actions of amdgpu_irq_add_id(): - * 1. Register a set() function with base driver. - * Base driver will call set() function to enable/disable an - * interrupt in DC hardware. - * 2. Register amdgpu_dm_irq_handler(). - * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts - * coming from DC hardware. - * amdgpu_dm_irq_handler() will re-direct the interrupt to DC - * for acknowledging and handling. - */ - - /* Use VBLANK interrupt */ - for (i = 0; i < adev->mode_info.num_crtc; i++) { - src_id = vblank_d1 + i; - r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->crtc_irq); - if (r) { - drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n"); - return r; - } - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, src_id, 0); - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || - int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { - drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n"); - return -EINVAL; - } - - c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_crtc_high_irq, c_irq_params)) - return -ENOMEM; - } - - if (dc_supports_vrr(adev->dm.dc->ctx->dce_version)) { - /* Use VUPDATE interrupt */ - for (i = 0; i < adev->mode_info.num_crtc; i++) { - src_id = VISLANDS30_IV_SRCID_D1_V_UPDATE_INT + i * 2; - r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->vupdate_irq); - if (r) { - drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n"); - return r; - } - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, src_id, 0); - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_VUPDATE1 || - int_params.irq_source > DC_IRQ_SOURCE_VUPDATE6) { - drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n"); - return -EINVAL; - } - - c_irq_params = &adev->dm.vupdate_params[ - int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_vupdate_high_irq, c_irq_params)) - return -ENOMEM; - } - } - - /* Use GRPH_PFLIP interrupt */ - for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP; - i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) { - r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq); - if (r) { - drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n"); - return r; - } - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, i, 0); - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || - int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { - drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n"); - return -EINVAL; - } - - c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_pflip_high_irq, c_irq_params)) - return -ENOMEM; - } - - /* HPD */ - r = amdgpu_irq_add_id(adev, client_id, - VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq); - if (r) { - drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n"); - return r; - } - - r = register_hpd_handlers(adev); - - return r; -} - -/* Register IRQ sources and initialize IRQ callbacks */ -static int dcn10_register_irq_handlers(struct amdgpu_device *adev) -{ - struct dc *dc = adev->dm.dc; - struct common_irq_params *c_irq_params; - struct dc_interrupt_params int_params = {0}; - int r; - int i; -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - static const unsigned int vrtl_int_srcid[] = { - DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL, - DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL, - DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL, - DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL, - DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL, - DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL - }; -#endif - - int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; - int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; - - /* - * Actions of amdgpu_irq_add_id(): - * 1. Register a set() function with base driver. - * Base driver will call set() function to enable/disable an - * interrupt in DC hardware. - * 2. Register amdgpu_dm_irq_handler(). - * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts - * coming from DC hardware. - * amdgpu_dm_irq_handler() will re-direct the interrupt to DC - * for acknowledging and handling. - */ - - /* Use VSTARTUP interrupt */ - for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP; - i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1; - i++) { - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq); - - if (r) { - drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n"); - return r; - } - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, i, 0); - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || - int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { - drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n"); - return -EINVAL; - } - - c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_crtc_high_irq, c_irq_params)) - return -ENOMEM; - } - - /* Use otg vertical line interrupt */ -#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) - for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) { - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, - vrtl_int_srcid[i], &adev->vline0_irq); - - if (r) { - drm_err(adev_to_drm(adev), "Failed to add vline0 irq id!\n"); - return r; - } - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0); - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 || - int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) { - drm_err(adev_to_drm(adev), "Failed to register vline0 irq!\n"); - return -EINVAL; - } - - c_irq_params = &adev->dm.vline0_params[int_params.irq_source - - DC_IRQ_SOURCE_DC1_VLINE0]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_dcn_vertical_interrupt0_high_irq, - c_irq_params)) - return -ENOMEM; - } -#endif - - /* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to - * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx - * to trigger at end of each vblank, regardless of state of the lock, - * matching DCE behaviour. - */ - for (i = DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT; - i <= DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT + adev->mode_info.num_crtc - 1; - i++) { - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->vupdate_irq); - - if (r) { - drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n"); - return r; - } - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, i, 0); - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_VUPDATE1 || - int_params.irq_source > DC_IRQ_SOURCE_VUPDATE6) { - drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n"); - return -EINVAL; - } - - c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_vupdate_high_irq, c_irq_params)) - return -ENOMEM; - } - - /* Use GRPH_PFLIP interrupt */ - for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT; - i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num - 1; - i++) { - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq); - if (r) { - drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n"); - return r; - } - - int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, i, 0); - - if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || - int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || - int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { - drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n"); - return -EINVAL; - } - - c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_pflip_high_irq, c_irq_params)) - return -ENOMEM; - } - - /* HPD */ - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, - &adev->hpd_irq); - if (r) { - drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n"); - return r; - } - - r = register_hpd_handlers(adev); - - return r; -} -/* Register Outbox IRQ sources and initialize IRQ callbacks */ -static int register_outbox_irq_handlers(struct amdgpu_device *adev) -{ - struct dc *dc = adev->dm.dc; - struct common_irq_params *c_irq_params; - struct dc_interrupt_params int_params = {0}; - int r, i; - - int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; - int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; - - r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT, - &adev->dmub_outbox_irq); - if (r) { - drm_err(adev_to_drm(adev), "Failed to add outbox irq id!\n"); - return r; - } - - if (dc->ctx->dmub_srv) { - i = DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT; - int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; - int_params.irq_source = - dc_interrupt_to_irq_source(dc, i, 0); - - c_irq_params = &adev->dm.dmub_outbox_params[0]; - - c_irq_params->adev = adev; - c_irq_params->irq_src = int_params.irq_source; - - if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, - dm_dmub_outbox1_low_irq, c_irq_params)) - return -ENOMEM; - } - - return 0; -} - /* * Acquires the lock for the atomic state object and returns * the new atomic state. @@ -5201,420 +2377,6 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev) return 0; } -#define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12 -#define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255 -#define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2) -#define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50 - -void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, - int bl_idx) -{ - struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[bl_idx]; - - if (caps->caps_valid) - return; - -#if defined(CONFIG_ACPI) - amdgpu_acpi_get_backlight_caps(caps); - - /* validate the firmware value is sane */ - if (caps->caps_valid) { - int spread = caps->max_input_signal - caps->min_input_signal; - - if (caps->max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || - caps->min_input_signal < 0 || - spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || - spread < AMDGPU_DM_MIN_SPREAD) { - drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n", - caps->min_input_signal, caps->max_input_signal); - caps->caps_valid = false; - } - } - - if (!caps->caps_valid) { - caps->min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; - caps->max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; - caps->caps_valid = true; - } -#else - if (caps->aux_support) - return; - - caps->min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; - caps->max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; - caps->caps_valid = true; -#endif -} - -static int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps, - unsigned int *min, unsigned int *max) -{ - if (!caps) - return 0; - - if (caps->aux_support) { - // Firmware limits are in nits, DC API wants millinits. - *max = 1000 * caps->aux_max_input_signal; - *min = 1000 * caps->aux_min_input_signal; - } else { - // Firmware limits are 8-bit, PWM control is 16-bit. - *max = 0x101 * caps->max_input_signal; - *min = 0x101 * caps->min_input_signal; - } - return 1; -} - -/* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */ -static inline u32 scale_input_to_fw(int min, int max, u64 input) -{ - return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min); -} - -/* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */ -static inline u32 scale_fw_to_input(int min, int max, u64 input) -{ - return min + DIV_ROUND_CLOSEST_ULL(input * (max - min), AMDGPU_MAX_BL_LEVEL); -} - -static void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps, - unsigned int min, unsigned int max, - uint32_t *user_brightness) -{ - u32 brightness = scale_input_to_fw(min, max, *user_brightness); - u8 lower_signal, upper_signal, upper_lum, lower_lum, lum; - int left, right; - - if (amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE) - return; - - if (!caps->data_points) - return; - - /* - * Handle the case where brightness is below the first data point - * Interpolate between (0,0) and (first_signal, first_lum) - */ - if (brightness < caps->luminance_data[0].input_signal) { - lum = DIV_ROUND_CLOSEST(caps->luminance_data[0].luminance * brightness, - caps->luminance_data[0].input_signal); - goto scale; - } - - left = 0; - right = caps->data_points - 1; - while (left <= right) { - int mid = left + (right - left) / 2; - u8 signal = caps->luminance_data[mid].input_signal; - - /* Exact match found */ - if (signal == brightness) { - lum = caps->luminance_data[mid].luminance; - goto scale; - } - - if (signal < brightness) - left = mid + 1; - else - right = mid - 1; - } - - /* verify bound */ - if (left >= caps->data_points) - left = caps->data_points - 1; - - /* At this point, left > right */ - lower_signal = caps->luminance_data[right].input_signal; - upper_signal = caps->luminance_data[left].input_signal; - lower_lum = caps->luminance_data[right].luminance; - upper_lum = caps->luminance_data[left].luminance; - - /* interpolate */ - if (right == left || !lower_lum) - lum = upper_lum; - else - lum = lower_lum + DIV_ROUND_CLOSEST((upper_lum - lower_lum) * - (brightness - lower_signal), - upper_signal - lower_signal); -scale: - *user_brightness = scale_fw_to_input(min, max, - DIV_ROUND_CLOSEST(lum * brightness, 101)); -} - -static u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps, - uint32_t brightness) -{ - unsigned int min, max; - - if (!get_brightness_range(caps, &min, &max)) - return brightness; - - convert_custom_brightness(caps, min, max, &brightness); - - // Rescale 0..max to min..max - return min + DIV_ROUND_CLOSEST_ULL((u64)(max - min) * brightness, max); -} - -static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps, - uint32_t brightness) -{ - unsigned int min, max; - - if (!get_brightness_range(caps, &min, &max)) - return brightness; - - if (brightness < min) - return 0; - // Rescale min..max to 0..max - return DIV_ROUND_CLOSEST_ULL((u64)max * (brightness - min), - max - min); -} - -static struct dc_stream_state *dm_find_stream_with_link( - struct amdgpu_display_manager *dm, - struct dc_link *link) -{ - struct dc_state *cur_dc_state = dm->dc->current_state; - struct dc_stream_state *stream = NULL; - int i; - - for (i = 0; i < cur_dc_state->stream_count; i++) { - stream = cur_dc_state->streams[i]; - if (stream->link == link) - return stream; - } - - return NULL; -} - -static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, - int bl_idx, - u32 user_brightness) -{ - struct amdgpu_dm_backlight_caps *caps; - struct dc_link *link; - u32 brightness = 0; - bool rc = false, reallow_idle = false; - struct drm_connector *connector; - struct dc_stream_state *stream; - unsigned int min, max; - - list_for_each_entry(connector, &dm->ddev->mode_config.connector_list, head) { - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - - if (aconnector->bl_idx != bl_idx) - continue; - - /* if connector is off, save the brightness for next time it's on */ - if (!aconnector->base.encoder) { - dm->brightness[bl_idx] = user_brightness; - dm->actual_brightness[bl_idx] = 0; - return; - } - } - - amdgpu_dm_update_backlight_caps(dm, bl_idx); - caps = &dm->backlight_caps[bl_idx]; - - dm->brightness[bl_idx] = user_brightness; - /* update scratch register */ - if (bl_idx == 0) - amdgpu_atombios_scratch_regs_set_backlight_level(dm->adev, dm->brightness[bl_idx]); - brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]); - link = (struct dc_link *)dm->backlight_link[bl_idx]; - - /* Apply brightness quirk */ - if (caps->brightness_mask) - brightness |= caps->brightness_mask; - - if (trace_amdgpu_dm_brightness_enabled()) { - trace_amdgpu_dm_brightness(__builtin_return_address(0), - user_brightness, - brightness, - caps->aux_support, - power_supply_is_system_supplied() > 0); - } - - stream = dm_find_stream_with_link(dm, link); - if (!stream) - return; - - mutex_lock(&dm->dc_lock); - if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) { - dc_allow_idle_optimizations(dm->dc, false); - reallow_idle = true; - } - - if (caps->aux_support) { - rc = mod_power_set_backlight_nits(dm->power_module, stream, brightness, - AUX_BL_DEFAULT_TRANSITION_TIME_MS, false, true); - } else { - /* power module uses millipercent */ - get_brightness_range(caps, &min, &max); - brightness = DIV_ROUND_CLOSEST(brightness * 100, (max - min)) * 1000; - rc = mod_power_set_backlight_percent(dm->power_module, stream, - brightness, 0, false); - } - - /* - * Some kms clients create a ramped backlight transition effect - * by rapidly changing the backlight. Yet we must wait on dmcub - * fw to exit psr/replay before programming backlight. To - * prevent lag, keep disable psr/replay and let the next atomic - * flip clear the event. - * - * ToDo: use ISM to handle rapidly backlight change - * - * Rapidly backlight change is similar to rapidly cursor events, - * which is now handled by ISM. ISM can delay the event until system - * is really idle, so we may use ISM to handle backlight change as well. - */ - amdgpu_dm_psr_set_event(dm, stream, true, - psr_event_hw_programming, true); - amdgpu_dm_replay_set_event(dm, stream, true, - replay_event_hw_programming, true); - - if (dm->dc->caps.ips_support && reallow_idle) - dc_allow_idle_optimizations(dm->dc, true); - - mutex_unlock(&dm->dc_lock); - - if (rc) - dm->actual_brightness[bl_idx] = user_brightness; -} - -static int amdgpu_dm_backlight_update_status(struct backlight_device *bd) -{ - struct amdgpu_display_manager *dm = bl_get_data(bd); - int i; - - for (i = 0; i < dm->num_of_edps; i++) { - if (bd == dm->backlight_dev[i]) - break; - } - if (i >= AMDGPU_DM_MAX_NUM_EDP) - i = 0; - amdgpu_dm_backlight_set_level(dm, i, bd->props.brightness); - - return 0; -} - -static u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm, - int bl_idx) -{ - int ret; - struct amdgpu_dm_backlight_caps caps; - struct dc_link *link = (struct dc_link *)dm->backlight_link[bl_idx]; - - amdgpu_dm_update_backlight_caps(dm, bl_idx); - caps = dm->backlight_caps[bl_idx]; - - if (caps.aux_support) { - u32 avg, peak; - - if (!dc_link_get_backlight_level_nits(link, &avg, &peak)) - return dm->brightness[bl_idx]; - return convert_brightness_to_user(&caps, avg); - } - - ret = dc_link_get_backlight_level(link); - - if (ret == DC_ERROR_UNEXPECTED) - return dm->brightness[bl_idx]; - - return convert_brightness_to_user(&caps, ret); -} - -static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd) -{ - struct amdgpu_display_manager *dm = bl_get_data(bd); - int i; - - for (i = 0; i < dm->num_of_edps; i++) { - if (bd == dm->backlight_dev[i]) - break; - } - if (i >= AMDGPU_DM_MAX_NUM_EDP) - i = 0; - return amdgpu_dm_backlight_get_level(dm, i); -} - -static const struct backlight_ops amdgpu_dm_backlight_ops = { - .options = BL_CORE_SUSPENDRESUME, - .get_brightness = amdgpu_dm_backlight_get_brightness, - .update_status = amdgpu_dm_backlight_update_status, -}; - -static void -amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) -{ - struct drm_device *drm = aconnector->base.dev; - struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm; - struct backlight_properties props = { 0 }; - struct amdgpu_dm_backlight_caps *caps; - char bl_name[16]; - int min, max; - int real_brightness; - int init_brightness; - - if (aconnector->bl_idx == -1) - return; - - if (!acpi_video_backlight_use_native()) { - drm_info(drm, "Skipping amdgpu DM backlight registration\n"); - /* Try registering an ACPI video backlight device instead. */ - acpi_video_register_backlight(); - return; - } - - caps = &dm->backlight_caps[aconnector->bl_idx]; - if (get_brightness_range(caps, &min, &max)) { - if (power_supply_is_system_supplied() > 0) - props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->ac_level, 100); - else - props.brightness = DIV_ROUND_CLOSEST((max - min) * caps->dc_level, 100); - /* min is zero, so max needs to be adjusted */ - props.max_brightness = max - min; - drm_dbg(drm, "Backlight caps: min: %d, max: %d, ac %d, dc %d\n", min, max, - caps->ac_level, caps->dc_level); - } else - props.brightness = props.max_brightness = MAX_BACKLIGHT_LEVEL; - - init_brightness = props.brightness; - - if (caps->data_points && !(amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE)) { - drm_info(drm, "Using custom brightness curve\n"); - props.scale = BACKLIGHT_SCALE_NON_LINEAR; - } else - props.scale = BACKLIGHT_SCALE_LINEAR; - props.type = BACKLIGHT_RAW; - - snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d", - drm->primary->index + aconnector->bl_idx); - - dm->backlight_dev[aconnector->bl_idx] = - backlight_device_register(bl_name, aconnector->base.kdev, dm, - &amdgpu_dm_backlight_ops, &props); - dm->brightness[aconnector->bl_idx] = props.brightness; - - if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) { - drm_err(drm, "DM: Backlight registration failed!\n"); - dm->backlight_dev[aconnector->bl_idx] = NULL; - } else { - /* - * dm->brightness[x] can be inconsistent just after startup until - * ops.get_brightness is called. - */ - real_brightness = - amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]); - - if (real_brightness != init_brightness) { - dm->actual_brightness[aconnector->bl_idx] = real_brightness; - dm->brightness[aconnector->bl_idx] = real_brightness; - } - drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name); - } -} - static int initialize_plane(struct amdgpu_display_manager *dm, struct amdgpu_mode_info *mode_info, int plane_id, enum drm_plane_type plane_type, @@ -5656,42 +2418,6 @@ static int initialize_plane(struct amdgpu_display_manager *dm, } -static void setup_backlight_device(struct amdgpu_display_manager *dm, - struct amdgpu_dm_connector *aconnector) -{ - struct amdgpu_dm_backlight_caps *caps; - struct dc_link *link = aconnector->dc_link; - int bl_idx = dm->num_of_edps; - - if (!(link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) || - link->type == dc_connection_none) - return; - - if (dm->num_of_edps >= AMDGPU_DM_MAX_NUM_EDP) { - drm_warn(adev_to_drm(dm->adev), "Too much eDP connections, skipping backlight setup for additional eDPs\n"); - return; - } - - aconnector->bl_idx = bl_idx; - - amdgpu_dm_update_backlight_caps(dm, bl_idx); - dm->backlight_link[bl_idx] = link; - dm->num_of_edps++; - - update_connector_ext_caps(aconnector); - caps = &dm->backlight_caps[aconnector->bl_idx]; - - /* Only offer ABM property when non-OLED and user didn't turn off by module parameter */ - if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0) - drm_object_attach_property(&aconnector->base.base, - dm->adev->mode_info.abm_level_property, - ABM_SYSFS_CONTROL); -} - -static void amdgpu_set_panel_orientation(struct drm_connector *connector); - - - /* * In this architecture, the association * connector -> encoder -> crtc @@ -5803,7 +2529,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case IP_VERSION(4, 0, 1): case IP_VERSION(4, 2, 0): case IP_VERSION(4, 2, 1): - if (register_outbox_irq_handlers(dm->adev)) { + if (amdgpu_dm_register_outbox_irq_handlers(dm->adev)) { drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n"); goto fail; } @@ -5916,7 +2642,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); if (aconnector->base.force && new_connection_type == dc_connection_none) { - emulated_link_detect(link); + amdgpu_dm_emulated_link_detect(link); amdgpu_dm_update_connector_after_detect(aconnector); } else { bool ret = false; @@ -5928,7 +2654,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) if (ret) { amdgpu_dm_update_connector_after_detect(aconnector); - setup_backlight_device(dm, aconnector); + amdgpu_dm_setup_backlight_device(dm, aconnector); /* Disable PSR if Replay can be enabled */ if (replay_feature_enabled) @@ -5980,7 +2706,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case CHIP_VEGA10: case CHIP_VEGA12: case CHIP_VEGA20: - if (dce110_register_irq_handlers(dm->adev)) { + if (amdgpu_dm_dce110_register_irq_handlers(dm->adev)) { drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n"); goto fail; } @@ -6010,7 +2736,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) case IP_VERSION(4, 0, 1): case IP_VERSION(4, 2, 0): case IP_VERSION(4, 2, 1): - if (dcn10_register_irq_handlers(dm->adev)) { + if (amdgpu_dm_dcn10_register_irq_handlers(dm->adev)) { drm_err(adev_to_drm(adev), "DM: Failed to initialize IRQ\n"); goto fail; } @@ -6101,78 +2827,6 @@ DEVICE_ATTR_WO(s3_debug); #endif -static int dm_init_microcode(struct amdgpu_device *adev) -{ - char *fw_name_dmub; - int r; - - switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { - case IP_VERSION(2, 1, 0): - fw_name_dmub = FIRMWARE_RENOIR_DMUB; - if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) - fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB; - break; - case IP_VERSION(3, 0, 0): - if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 0)) - fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB; - else - fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB; - break; - case IP_VERSION(3, 0, 1): - fw_name_dmub = FIRMWARE_VANGOGH_DMUB; - break; - case IP_VERSION(3, 0, 2): - fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB; - break; - case IP_VERSION(3, 0, 3): - fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB; - break; - case IP_VERSION(3, 1, 2): - case IP_VERSION(3, 1, 3): - fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB; - break; - case IP_VERSION(3, 1, 4): - fw_name_dmub = FIRMWARE_DCN_314_DMUB; - break; - case IP_VERSION(3, 1, 5): - fw_name_dmub = FIRMWARE_DCN_315_DMUB; - break; - case IP_VERSION(3, 1, 6): - fw_name_dmub = FIRMWARE_DCN316_DMUB; - break; - case IP_VERSION(3, 2, 0): - fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB; - break; - case IP_VERSION(3, 2, 1): - fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB; - break; - case IP_VERSION(3, 5, 0): - fw_name_dmub = FIRMWARE_DCN_35_DMUB; - break; - case IP_VERSION(3, 5, 1): - fw_name_dmub = FIRMWARE_DCN_351_DMUB; - break; - case IP_VERSION(3, 6, 0): - fw_name_dmub = FIRMWARE_DCN_36_DMUB; - break; - case IP_VERSION(4, 0, 1): - fw_name_dmub = FIRMWARE_DCN_401_DMUB; - break; - case IP_VERSION(4, 2, 0): - fw_name_dmub = FIRMWARE_DCN_42_DMUB; - break; - case IP_VERSION(4, 2, 1): - fw_name_dmub = FIRMWARE_DCN_42B_DMUB; - break; - default: - /* ASIC doesn't support DMUB. */ - return 0; - } - r = amdgpu_ucode_request(adev, &adev->dm.dmub_fw, AMDGPU_UCODE_REQUIRED, - "%s", fw_name_dmub); - return r; -} - static int dm_early_init(struct amdgpu_ip_block *ip_block) { struct amdgpu_device *adev = ip_block->adev; @@ -6323,22 +2977,13 @@ static int dm_early_init(struct amdgpu_ip_block *ip_block) return dm_init_microcode(adev); } -static bool modereset_required(struct drm_crtc_state *crtc_state) +STATIC_IFN_KUNIT bool modereset_required(struct drm_crtc_state *crtc_state) { return !crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state); } +EXPORT_IF_KUNIT(modereset_required); -static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder) -{ - drm_encoder_cleanup(encoder); - kfree(encoder); -} - -static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = { - .destroy = amdgpu_dm_encoder_destroy, -}; - -static int +STATIC_IFN_KUNIT int fill_plane_color_attributes(const struct drm_plane_state *plane_state, const enum surface_pixel_format format, enum dc_color_space *color_space) @@ -6385,6 +3030,7 @@ fill_plane_color_attributes(const struct drm_plane_state *plane_state, return 0; } +EXPORT_IF_KUNIT(fill_plane_color_attributes); static int fill_dc_plane_info_and_addr(struct amdgpu_device *adev, @@ -6620,8 +3266,8 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, { struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(crtc_state); struct rect *dirty_rects = flip_addrs->dirty_rects; - u32 num_clips; - struct drm_mode_rect *clips; + u32 num_clips = 0; + struct drm_mode_rect *clips = NULL; bool bb_changed; bool fb_changed; u32 i = 0; @@ -6637,8 +3283,10 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, if (new_plane_state->rotation != DRM_MODE_ROTATE_0) goto ffu; - num_clips = drm_plane_get_damage_clips_count(new_plane_state); - clips = drm_plane_get_damage_clips(new_plane_state); + if (!new_plane_state->ignore_damage_clips) { + num_clips = drm_plane_get_damage_clips_count(new_plane_state); + clips = drm_plane_get_damage_clips(new_plane_state); + } if (num_clips && (!amdgpu_damage_clips || (amdgpu_damage_clips < 0 && is_psr_su))) @@ -6721,7 +3369,7 @@ static void fill_dc_dirty_rects(struct drm_plane *plane, &flip_addrs->dirty_rect_count, true); } -static void update_stream_scaling_settings(struct drm_device *dev, +void amdgpu_dm_update_stream_scaling_settings(struct drm_device *dev, const struct drm_display_mode *mode, const struct dm_connector_state *dm_state, struct dc_stream_state *stream) @@ -6777,2111 +3425,6 @@ static void update_stream_scaling_settings(struct drm_device *dev, } -static enum dc_color_depth -convert_color_depth_from_display_info(const struct drm_connector *connector, - bool is_y420, int requested_bpc) -{ - u8 bpc; - - if (is_y420) { - bpc = 8; - - /* Cap display bpc based on HDMI 2.0 HF-VSDB */ - if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) - bpc = 16; - else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) - bpc = 12; - else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) - bpc = 10; - } else { - bpc = (uint8_t)connector->display_info.bpc; - /* Assume 8 bpc by default if no bpc is specified. */ - bpc = bpc ? bpc : 8; - } - - if (requested_bpc > 0) { - /* - * Cap display bpc based on the user requested value. - * - * The value for state->max_bpc may not correctly updated - * depending on when the connector gets added to the state - * or if this was called outside of atomic check, so it - * can't be used directly. - */ - bpc = min_t(u8, bpc, requested_bpc); - - /* Round down to the nearest even number. */ - bpc = bpc - (bpc & 1); - } - - switch (bpc) { - case 0: - /* - * Temporary Work around, DRM doesn't parse color depth for - * EDID revision before 1.4 - * TODO: Fix edid parsing - */ - return COLOR_DEPTH_888; - case 6: - return COLOR_DEPTH_666; - case 8: - return COLOR_DEPTH_888; - case 10: - return COLOR_DEPTH_101010; - case 12: - return COLOR_DEPTH_121212; - case 14: - return COLOR_DEPTH_141414; - case 16: - return COLOR_DEPTH_161616; - default: - return COLOR_DEPTH_UNDEFINED; - } -} - -static enum dc_aspect_ratio -get_aspect_ratio(const struct drm_display_mode *mode_in) -{ - /* 1-1 mapping, since both enums follow the HDMI spec. */ - return (enum dc_aspect_ratio) mode_in->picture_aspect_ratio; -} - -static enum dc_color_space -get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, - const struct drm_connector_state *connector_state) -{ - enum dc_color_space color_space = COLOR_SPACE_SRGB; - - switch (connector_state->colorspace) { - case DRM_MODE_COLORIMETRY_BT601_YCC: - if (dc_crtc_timing->flags.Y_ONLY) - color_space = COLOR_SPACE_YCBCR601_LIMITED; - else - color_space = COLOR_SPACE_YCBCR601; - break; - case DRM_MODE_COLORIMETRY_BT709_YCC: - if (dc_crtc_timing->flags.Y_ONLY) - color_space = COLOR_SPACE_YCBCR709_LIMITED; - else - color_space = COLOR_SPACE_YCBCR709; - break; - case DRM_MODE_COLORIMETRY_OPRGB: - color_space = COLOR_SPACE_ADOBERGB; - break; - case DRM_MODE_COLORIMETRY_BT2020_RGB: - case DRM_MODE_COLORIMETRY_BT2020_YCC: - if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) - color_space = COLOR_SPACE_2020_RGB_FULLRANGE; - else - color_space = COLOR_SPACE_2020_YCBCR_LIMITED; - break; - case DRM_MODE_COLORIMETRY_DEFAULT: // ITU601 - default: - if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) { - color_space = COLOR_SPACE_SRGB; - if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED) - color_space = COLOR_SPACE_SRGB_LIMITED; - /* - * 27030khz is the separation point between HDTV and SDTV - * according to HDMI spec, we use YCbCr709 and YCbCr601 - * respectively - */ - } else if (dc_crtc_timing->pix_clk_100hz > 270300) { - if (dc_crtc_timing->flags.Y_ONLY) - color_space = - COLOR_SPACE_YCBCR709_LIMITED; - else - color_space = COLOR_SPACE_YCBCR709; - } else { - if (dc_crtc_timing->flags.Y_ONLY) - color_space = - COLOR_SPACE_YCBCR601_LIMITED; - else - color_space = COLOR_SPACE_YCBCR601; - } - break; - } - - return color_space; -} - -static enum display_content_type -get_output_content_type(const struct drm_connector_state *connector_state) -{ - switch (connector_state->content_type) { - default: - case DRM_MODE_CONTENT_TYPE_NO_DATA: - return DISPLAY_CONTENT_TYPE_NO_DATA; - case DRM_MODE_CONTENT_TYPE_GRAPHICS: - return DISPLAY_CONTENT_TYPE_GRAPHICS; - case DRM_MODE_CONTENT_TYPE_PHOTO: - return DISPLAY_CONTENT_TYPE_PHOTO; - case DRM_MODE_CONTENT_TYPE_CINEMA: - return DISPLAY_CONTENT_TYPE_CINEMA; - case DRM_MODE_CONTENT_TYPE_GAME: - return DISPLAY_CONTENT_TYPE_GAME; - } -} - -static bool adjust_colour_depth_from_display_info( - struct dc_crtc_timing *timing_out, - const struct drm_display_info *info) -{ - enum dc_color_depth depth = timing_out->display_color_depth; - int normalized_clk; - - do { - normalized_clk = timing_out->pix_clk_100hz / 10; - /* YCbCr 4:2:0 requires additional adjustment of 1/2 */ - if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420) - normalized_clk /= 2; - /* Adjusting pix clock following on HDMI spec based on colour depth */ - switch (depth) { - case COLOR_DEPTH_888: - break; - case COLOR_DEPTH_101010: - normalized_clk = (normalized_clk * 30) / 24; - break; - case COLOR_DEPTH_121212: - normalized_clk = (normalized_clk * 36) / 24; - break; - case COLOR_DEPTH_161616: - normalized_clk = (normalized_clk * 48) / 24; - break; - default: - /* The above depths are the only ones valid for HDMI. */ - return false; - } - if (normalized_clk <= info->max_tmds_clock) { - timing_out->display_color_depth = depth; - return true; - } - } while (--depth > COLOR_DEPTH_666); - return false; -} - -static void fill_stream_properties_from_drm_display_mode( - struct dc_stream_state *stream, - const struct drm_display_mode *mode_in, - const struct drm_connector *connector, - const struct drm_connector_state *connector_state, - const struct dc_stream_state *old_stream, - int requested_bpc) -{ - bool is_dp_or_hdmi = dc_is_hdmi_signal(stream->signal) || dc_is_dp_signal(stream->signal); - struct dc_crtc_timing *timing_out = &stream->timing; - const struct drm_display_info *info = &connector->display_info; - struct amdgpu_dm_connector *aconnector = NULL; - struct hdmi_vendor_infoframe hv_frame; - struct hdmi_avi_infoframe avi_frame; - bool want_420; - bool want_422; - ssize_t err; - - if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) - aconnector = to_amdgpu_dm_connector(connector); - - memset(&hv_frame, 0, sizeof(hv_frame)); - memset(&avi_frame, 0, sizeof(avi_frame)); - - timing_out->h_border_left = 0; - timing_out->h_border_right = 0; - timing_out->v_border_top = 0; - timing_out->v_border_bottom = 0; - - want_420 = (aconnector && aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420) || - (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420); - want_422 = (aconnector && aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422) || - (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR422); - - if (drm_mode_is_420_only(info, mode_in) && - (want_420 || connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO)) { - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; - } else if (drm_mode_is_420_also(info, mode_in) && want_420) { - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; - } else if ((info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) && - want_422 && is_dp_or_hdmi) { - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422; - } else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 && - (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) && - is_dp_or_hdmi) { - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; - } else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444 || - connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO) { - timing_out->pixel_encoding = PIXEL_ENCODING_RGB; - } else { - /* - * If a format was explicitly requested but the requested format - * can't be satisfied, set it to an invalid value so that an - * error bubbles up to userspace. This way, userspace knows it - * needs to make a better choice. - */ - if (connector_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO) - timing_out->pixel_encoding = PIXEL_ENCODING_UNDEFINED; - else if (drm_mode_is_420_only(info, mode_in)) - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; - else - timing_out->pixel_encoding = PIXEL_ENCODING_RGB; - } - - timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE; - timing_out->display_color_depth = convert_color_depth_from_display_info( - connector, - (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420), - requested_bpc); - timing_out->scan_type = SCANNING_TYPE_NODATA; - timing_out->hdmi_vic = 0; - - if (old_stream) { - timing_out->vic = old_stream->timing.vic; - timing_out->flags.HSYNC_POSITIVE_POLARITY = old_stream->timing.flags.HSYNC_POSITIVE_POLARITY; - timing_out->flags.VSYNC_POSITIVE_POLARITY = old_stream->timing.flags.VSYNC_POSITIVE_POLARITY; - } else { - timing_out->vic = drm_match_cea_mode(mode_in); - if (mode_in->flags & DRM_MODE_FLAG_PHSYNC) - timing_out->flags.HSYNC_POSITIVE_POLARITY = 1; - if (mode_in->flags & DRM_MODE_FLAG_PVSYNC) - timing_out->flags.VSYNC_POSITIVE_POLARITY = 1; - } - - if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || - stream->signal == SIGNAL_TYPE_HDMI_FRL) { - err = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, - (struct drm_connector *)connector, - mode_in); - if (err < 0) - drm_warn_once(connector->dev, "Failed to setup avi infoframe on connector %s: %zd\n", - connector->name, err); - timing_out->vic = avi_frame.video_code; - err = drm_hdmi_vendor_infoframe_from_display_mode(&hv_frame, - (struct drm_connector *)connector, - mode_in); - if (err < 0) - drm_warn_once(connector->dev, "Failed to setup vendor infoframe on connector %s: %zd\n", - connector->name, err); - timing_out->hdmi_vic = hv_frame.vic; - } - - if (aconnector && is_freesync_video_mode(mode_in, aconnector)) { - timing_out->h_addressable = mode_in->hdisplay; - timing_out->h_total = mode_in->htotal; - timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start; - timing_out->h_front_porch = mode_in->hsync_start - mode_in->hdisplay; - timing_out->v_total = mode_in->vtotal; - timing_out->v_addressable = mode_in->vdisplay; - timing_out->v_front_porch = mode_in->vsync_start - mode_in->vdisplay; - timing_out->v_sync_width = mode_in->vsync_end - mode_in->vsync_start; - timing_out->pix_clk_100hz = mode_in->clock * 10; - } else { - timing_out->h_addressable = mode_in->crtc_hdisplay; - timing_out->h_total = mode_in->crtc_htotal; - timing_out->h_sync_width = mode_in->crtc_hsync_end - mode_in->crtc_hsync_start; - timing_out->h_front_porch = mode_in->crtc_hsync_start - mode_in->crtc_hdisplay; - timing_out->v_total = mode_in->crtc_vtotal; - timing_out->v_addressable = mode_in->crtc_vdisplay; - timing_out->v_front_porch = mode_in->crtc_vsync_start - mode_in->crtc_vdisplay; - timing_out->v_sync_width = mode_in->crtc_vsync_end - mode_in->crtc_vsync_start; - timing_out->pix_clk_100hz = mode_in->crtc_clock * 10; - } - - timing_out->aspect_ratio = get_aspect_ratio(mode_in); - - stream->out_transfer_func.type = TF_TYPE_PREDEFINED; - stream->out_transfer_func.tf = TRANSFER_FUNCTION_SRGB; - if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) { - if (!adjust_colour_depth_from_display_info(timing_out, info) && - drm_mode_is_420_also(info, mode_in) && - timing_out->pixel_encoding != PIXEL_ENCODING_YCBCR420) { - timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; - adjust_colour_depth_from_display_info(timing_out, info); - } - } - - stream->output_color_space = get_output_color_space(timing_out, connector_state); - stream->content_type = get_output_content_type(connector_state); -} - -static void fill_audio_info(struct audio_info *audio_info, - const struct drm_connector *drm_connector, - const struct dc_sink *dc_sink) -{ - int i = 0; - int cea_revision = 0; - const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps; - - audio_info->manufacture_id = edid_caps->manufacturer_id; - audio_info->product_id = edid_caps->product_id; - - cea_revision = drm_connector->display_info.cea_rev; - - strscpy(audio_info->display_name, - edid_caps->display_name, - AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS); - - if (cea_revision >= 3) { - audio_info->mode_count = edid_caps->audio_mode_count; - - for (i = 0; i < audio_info->mode_count; ++i) { - audio_info->modes[i].format_code = - (enum audio_format_code) - (edid_caps->audio_modes[i].format_code); - audio_info->modes[i].channel_count = - edid_caps->audio_modes[i].channel_count; - audio_info->modes[i].sample_rates.all = - edid_caps->audio_modes[i].sample_rate; - audio_info->modes[i].sample_size = - edid_caps->audio_modes[i].sample_size; - } - } - - audio_info->flags.all = edid_caps->speaker_flags; - - /* TODO: We only check for the progressive mode, check for interlace mode too */ - if (drm_connector->latency_present[0]) { - audio_info->video_latency = drm_connector->video_latency[0]; - audio_info->audio_latency = drm_connector->audio_latency[0]; - } - - /* TODO: For DP, video and audio latency should be calculated from DPCD caps */ - -} - -static void -copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode *src_mode, - struct drm_display_mode *dst_mode) -{ - dst_mode->crtc_hdisplay = src_mode->crtc_hdisplay; - dst_mode->crtc_vdisplay = src_mode->crtc_vdisplay; - dst_mode->crtc_clock = src_mode->crtc_clock; - dst_mode->crtc_hblank_start = src_mode->crtc_hblank_start; - dst_mode->crtc_hblank_end = src_mode->crtc_hblank_end; - dst_mode->crtc_hsync_start = src_mode->crtc_hsync_start; - dst_mode->crtc_hsync_end = src_mode->crtc_hsync_end; - dst_mode->crtc_htotal = src_mode->crtc_htotal; - dst_mode->crtc_hskew = src_mode->crtc_hskew; - dst_mode->crtc_vblank_start = src_mode->crtc_vblank_start; - dst_mode->crtc_vblank_end = src_mode->crtc_vblank_end; - dst_mode->crtc_vsync_start = src_mode->crtc_vsync_start; - dst_mode->crtc_vsync_end = src_mode->crtc_vsync_end; - dst_mode->crtc_vtotal = src_mode->crtc_vtotal; -} - -static void -decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode, - const struct drm_display_mode *native_mode, - bool scale_enabled) -{ - if (scale_enabled || ( - native_mode->clock == drm_mode->clock && - native_mode->htotal == drm_mode->htotal && - native_mode->vtotal == drm_mode->vtotal)) { - if (native_mode->crtc_clock) - copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode); - } else { - /* no scaling nor amdgpu inserted, no need to patch */ - } -} - -static struct dc_sink * -create_fake_sink(struct drm_device *dev, struct dc_link *link) -{ - struct dc_sink_init_data sink_init_data = { 0 }; - struct dc_sink *sink = NULL; - - sink_init_data.link = link; - sink_init_data.sink_signal = link->connector_signal; - - sink = dc_sink_create(&sink_init_data); - if (!sink) { - drm_err(dev, "Failed to create sink!\n"); - return NULL; - } - sink->sink_signal = SIGNAL_TYPE_VIRTUAL; - - return sink; -} - -static void set_multisync_trigger_params( - struct dc_stream_state *stream) -{ - struct dc_stream_state *master = NULL; - - if (stream->triggered_crtc_reset.enabled) { - master = stream->triggered_crtc_reset.event_source; - stream->triggered_crtc_reset.event = - master->timing.flags.VSYNC_POSITIVE_POLARITY ? - CRTC_EVENT_VSYNC_RISING : CRTC_EVENT_VSYNC_FALLING; - stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_PIXEL; - } -} - -static void set_master_stream(struct dc_stream_state *stream_set[], - int stream_count) -{ - int j, highest_rfr = 0, master_stream = 0; - - for (j = 0; j < stream_count; j++) { - if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) { - int refresh_rate = 0; - - refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/ - (stream_set[j]->timing.h_total*stream_set[j]->timing.v_total); - if (refresh_rate > highest_rfr) { - highest_rfr = refresh_rate; - master_stream = j; - } - } - } - for (j = 0; j < stream_count; j++) { - if (stream_set[j]) - stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream]; - } -} - -static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context) -{ - int i = 0; - struct dc_stream_state *stream; - - if (context->stream_count < 2) - return; - for (i = 0; i < context->stream_count ; i++) { - if (!context->streams[i]) - continue; - /* - * TODO: add a function to read AMD VSDB bits and set - * crtc_sync_master.multi_sync_enabled flag - * For now it's set to false - */ - } - - set_master_stream(context->streams, context->stream_count); - - for (i = 0; i < context->stream_count ; i++) { - stream = context->streams[i]; - - if (!stream) - continue; - - set_multisync_trigger_params(stream); - } -} - -/** - * DOC: FreeSync Video - * - * When a userspace application wants to play a video, the content follows a - * standard format definition that usually specifies the FPS for that format. - * The below list illustrates some video format and the expected FPS, - * respectively: - * - * - TV/NTSC (23.976 FPS) - * - Cinema (24 FPS) - * - TV/PAL (25 FPS) - * - TV/NTSC (29.97 FPS) - * - TV/NTSC (30 FPS) - * - Cinema HFR (48 FPS) - * - TV/PAL (50 FPS) - * - Commonly used (60 FPS) - * - Multiples of 24 (48,72,96 FPS) - * - * The list of standards video format is not huge and can be added to the - * connector modeset list beforehand. With that, userspace can leverage - * FreeSync to extends the front porch in order to attain the target refresh - * rate. Such a switch will happen seamlessly, without screen blanking or - * reprogramming of the output in any other way. If the userspace requests a - * modesetting change compatible with FreeSync modes that only differ in the - * refresh rate, DC will skip the full update and avoid blink during the - * transition. For example, the video player can change the modesetting from - * 60Hz to 30Hz for playing TV/NTSC content when it goes full screen without - * causing any display blink. This same concept can be applied to a mode - * setting change. - */ -static struct drm_display_mode * -get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector, - bool use_probed_modes) -{ - struct drm_display_mode *m, *m_pref = NULL; - u16 current_refresh, highest_refresh; - struct list_head *list_head = use_probed_modes ? - &aconnector->base.probed_modes : - &aconnector->base.modes; - - if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - return NULL; - - if (aconnector->freesync_vid_base.clock != 0) - return &aconnector->freesync_vid_base; - - /* Find the preferred mode */ - list_for_each_entry(m, list_head, head) { - if (m->type & DRM_MODE_TYPE_PREFERRED) { - m_pref = m; - break; - } - } - - if (!m_pref) { - /* Probably an EDID with no preferred mode. Fallback to first entry */ - m_pref = list_first_entry_or_null( - &aconnector->base.modes, struct drm_display_mode, head); - if (!m_pref) { - drm_dbg_driver(aconnector->base.dev, "No preferred mode found in EDID\n"); - return NULL; - } - } - - highest_refresh = drm_mode_vrefresh(m_pref); - - /* - * Find the mode with highest refresh rate with same resolution. - * For some monitors, preferred mode is not the mode with highest - * supported refresh rate. - */ - list_for_each_entry(m, list_head, head) { - current_refresh = drm_mode_vrefresh(m); - - if (m->hdisplay == m_pref->hdisplay && - m->vdisplay == m_pref->vdisplay && - highest_refresh < current_refresh) { - highest_refresh = current_refresh; - m_pref = m; - } - } - - drm_mode_copy(&aconnector->freesync_vid_base, m_pref); - return m_pref; -} - -static bool is_freesync_video_mode(const struct drm_display_mode *mode, - struct amdgpu_dm_connector *aconnector) -{ - struct drm_display_mode *high_mode; - int timing_diff; - - high_mode = get_highest_refresh_rate_mode(aconnector, false); - if (!high_mode || !mode) - return false; - - timing_diff = high_mode->vtotal - mode->vtotal; - - if (high_mode->clock == 0 || high_mode->clock != mode->clock || - high_mode->hdisplay != mode->hdisplay || - high_mode->vdisplay != mode->vdisplay || - high_mode->hsync_start != mode->hsync_start || - high_mode->hsync_end != mode->hsync_end || - high_mode->htotal != mode->htotal || - high_mode->hskew != mode->hskew || - high_mode->vscan != mode->vscan || - high_mode->vsync_start - mode->vsync_start != timing_diff || - high_mode->vsync_end - mode->vsync_end != timing_diff) - return false; - else - return true; -} - -#if defined(CONFIG_DRM_AMD_DC_FP) -static void update_dsc_caps(struct amdgpu_dm_connector *aconnector, - struct dc_sink *sink, struct dc_stream_state *stream, - struct dsc_dec_dpcd_caps *dsc_caps) -{ - stream->timing.flags.DSC = 0; - dsc_caps->is_dsc_supported = false; - - if (aconnector->dc_link && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT || - sink->sink_signal == SIGNAL_TYPE_EDP)) { - if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) - dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, - aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, - aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, - dsc_caps); - else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) { - if (aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT && - !aconnector->dsc_settings.dsc_force_disable_passthrough && - aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0 && - sink->edid_caps.frl_dsc_support && - sink->edid_caps.max_frl_rate > 0 && - sink->edid_caps.frl_dsc_max_frl_rate > 0) - dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps); - else - dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, - aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, - aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, - dsc_caps); - } - } else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) { - if (sink->edid_caps.frl_dsc_support && - sink->edid_caps.max_frl_rate > 0 && - sink->edid_caps.frl_dsc_max_frl_rate > 0) - dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps); - } -} - -static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector, - struct dc_sink *sink, struct dc_stream_state *stream, - struct dsc_dec_dpcd_caps *dsc_caps, - uint32_t max_dsc_target_bpp_limit_override) -{ - const struct dc_link_settings *verified_link_cap = NULL; - u32 link_bw_in_kbps; - u32 edp_min_bpp_x16, edp_max_bpp_x16; - struct dc *dc = sink->ctx->dc; - struct dc_dsc_bw_range bw_range = {0}; - struct dc_dsc_config dsc_cfg = {0}; - struct dc_dsc_config_options dsc_options = {0}; - - dc_dsc_get_default_config_option(dc, &dsc_options); - dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16; - - verified_link_cap = dc_link_get_link_cap(stream->link); - link_bw_in_kbps = dc_link_bandwidth_kbps(stream->link, verified_link_cap); - edp_min_bpp_x16 = 8 * 16; - edp_max_bpp_x16 = 8 * 16; - - if (edp_max_bpp_x16 > dsc_caps->edp_max_bits_per_pixel) - edp_max_bpp_x16 = dsc_caps->edp_max_bits_per_pixel; - - if (edp_max_bpp_x16 < edp_min_bpp_x16) - edp_min_bpp_x16 = edp_max_bpp_x16; - - if (dc_dsc_compute_bandwidth_range(dc->res_pool->dscs[0], - dc->debug.dsc_min_slice_height_override, - edp_min_bpp_x16, edp_max_bpp_x16, - dsc_caps, - &stream->timing, - dc_link_get_highest_encoding_format(aconnector->dc_link), - &bw_range)) { - - if (bw_range.max_kbps < link_bw_in_kbps) { - if (dc_dsc_compute_config(dc->res_pool->dscs[0], - dsc_caps, - &dsc_options, - 0, - &stream->timing, - dc_link_get_highest_encoding_format(aconnector->dc_link), - &dsc_cfg)) { - stream->timing.dsc_cfg = dsc_cfg; - stream->timing.flags.DSC = 1; - stream->timing.dsc_cfg.bits_per_pixel = edp_max_bpp_x16; - } - return; - } - } - - if (dc_dsc_compute_config(dc->res_pool->dscs[0], - dsc_caps, - &dsc_options, - link_bw_in_kbps, - &stream->timing, - dc_link_get_highest_encoding_format(aconnector->dc_link), - &dsc_cfg)) { - stream->timing.dsc_cfg = dsc_cfg; - stream->timing.flags.DSC = 1; - } -} - -static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, - struct dc_sink *sink, struct dc_stream_state *stream, - struct dsc_dec_dpcd_caps *dsc_caps) -{ - struct drm_connector *drm_connector = &aconnector->base; - u32 link_bandwidth_kbps; - struct dc *dc = sink->ctx->dc; - const struct dc_hdmi_frl_link_settings *frl_verified_link_cap = NULL; - u32 converter_bw_in_kbps; - u32 sink_bw_in_kbps; - u32 dsc_sink_bw_in_kbps; - u32 max_supported_bw_in_kbps, timing_bw_in_kbps; - u32 dsc_max_supported_bw_in_kbps; - u32 max_dsc_target_bpp_limit_override = - drm_connector->display_info.max_dsc_bpp; - struct dc_dsc_config_options dsc_options = {0}; - - dc_dsc_get_default_config_option(dc, &dsc_options); - dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16; - - link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, - dc_link_get_link_cap(aconnector->dc_link)); - - /* Set DSC policy according to dsc_clock_en */ - dc_dsc_policy_set_enable_dsc_when_not_needed( - aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE); - - if (sink->sink_signal == SIGNAL_TYPE_EDP && - !aconnector->dc_link->panel_config.dsc.disable_dsc_edp && - dc->caps.edp_dsc_support && aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE) { - - apply_dsc_policy_for_edp(aconnector, sink, stream, dsc_caps, max_dsc_target_bpp_limit_override); - - } else if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) { - if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) { - if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], - dsc_caps, - &dsc_options, - link_bandwidth_kbps, - &stream->timing, - dc_link_get_highest_encoding_format(aconnector->dc_link), - &stream->timing.dsc_cfg)) { - stream->timing.flags.DSC = 1; - drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from SST RX\n", - __func__, drm_connector->name); - } - } else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) { - timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing, - dc_link_get_highest_encoding_format(aconnector->dc_link)); - converter_bw_in_kbps = aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps; - sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.max_frl_rate); - dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate); - - if (dsc_caps->is_frl) { - max_supported_bw_in_kbps = min(link_bandwidth_kbps, converter_bw_in_kbps); - max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, sink_bw_in_kbps); - dsc_max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, dsc_sink_bw_in_kbps); - } else { - max_supported_bw_in_kbps = link_bandwidth_kbps; - dsc_max_supported_bw_in_kbps = link_bandwidth_kbps; - } - - if (timing_bw_in_kbps > max_supported_bw_in_kbps && - max_supported_bw_in_kbps > 0 && - dsc_max_supported_bw_in_kbps > 0) - if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], - dsc_caps, - &dsc_options, - dsc_max_supported_bw_in_kbps, - &stream->timing, - dc_link_get_highest_encoding_format(aconnector->dc_link), - &stream->timing.dsc_cfg)) { - stream->timing.flags.DSC = 1; - drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from %s\n", - __func__, drm_connector->name, - (dsc_caps->is_frl == 1) ? "HDMI FRL RX" : "DP-HDMI PCON"); - } - } - } - else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) { - struct dc_dsc_policy dsc_policy = {0}; - - frl_verified_link_cap = dc_link_get_frl_link_cap(stream->link); - if (frl_verified_link_cap->frl_link_rate != HDMI_FRL_LINK_RATE_DISABLE && - aconnector->dc_link->frl_flags.force_frl_dsc) { - dc_dsc_policy_set_enable_dsc_when_not_needed(true); - dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link)); - } - - timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing, DC_LINK_ENCODING_HDMI_FRL); - link_bandwidth_kbps = dc_link_frl_bandwidth_kbps(stream->link, frl_verified_link_cap->frl_link_rate); - dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate); - - if ((timing_bw_in_kbps > link_bandwidth_kbps && dsc_sink_bw_in_kbps > 0) || - (dsc_policy.enable_dsc_when_not_needed || dsc_options.force_dsc_when_not_needed)) { - if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], - dsc_caps, - &dsc_options, - dsc_sink_bw_in_kbps, - &stream->timing, - dc_link_get_highest_encoding_format(aconnector->dc_link), - &stream->timing.dsc_cfg)) { - stream->timing.flags.DSC = 1; - drm_dbg_driver(drm_connector->dev, "%s: HDMI_FRL_DSC [%s] DSC is selected from HDMI FRL RX\n", - __func__, drm_connector->name); - } - } - } - - /* Overwrite the stream flag if DSC is enabled through debugfs */ - if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE) - stream->timing.flags.DSC = 1; - - if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_h) - stream->timing.dsc_cfg.num_slices_h = aconnector->dsc_settings.dsc_num_slices_h; - - if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_v) - stream->timing.dsc_cfg.num_slices_v = aconnector->dsc_settings.dsc_num_slices_v; - - if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel) - stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel; -} -#endif - -static struct dc_stream_state * -create_stream_for_sink(struct drm_connector *connector, - const struct drm_display_mode *drm_mode, - const struct dm_connector_state *dm_state, - const struct dc_stream_state *old_stream, - int requested_bpc) -{ - struct drm_device *dev = connector->dev; - struct amdgpu_dm_connector *aconnector = NULL; - struct drm_display_mode *preferred_mode = NULL; - const struct drm_connector_state *con_state = &dm_state->base; - struct dc_stream_state *stream = NULL; - struct drm_display_mode mode; - struct drm_display_mode saved_mode; - struct drm_display_mode *freesync_mode = NULL; - bool native_mode_found = false; - bool recalculate_timing = false; - bool scale = dm_state->scaling != RMX_OFF; - int mode_refresh; - int preferred_refresh = 0; - enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN; -#if defined(CONFIG_DRM_AMD_DC_FP) - struct dsc_dec_dpcd_caps dsc_caps = {0}; -#endif - struct dc_link *link = NULL; - struct dc_sink *sink = NULL; - - drm_mode_init(&mode, drm_mode); - memset(&saved_mode, 0, sizeof(saved_mode)); - - if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) { - aconnector = NULL; - aconnector = to_amdgpu_dm_connector(connector); - link = aconnector->dc_link; - } else { - struct drm_writeback_connector *wbcon = NULL; - struct amdgpu_dm_wb_connector *dm_wbcon = NULL; - - wbcon = drm_connector_to_writeback(connector); - dm_wbcon = to_amdgpu_dm_wb_connector(wbcon); - link = dm_wbcon->link; - } - - if (!aconnector || !aconnector->dc_sink) { - sink = create_fake_sink(dev, link); - if (!sink) - return stream; - - } else { - sink = aconnector->dc_sink; - dc_sink_retain(sink); - } - - stream = dc_create_stream_for_sink(sink); - - if (stream == NULL) { - drm_err(dev, "Failed to create stream for sink!\n"); - goto finish; - } - - /* We leave this NULL for writeback connectors */ - stream->dm_stream_context = aconnector; - - stream->timing.flags.LTE_340MCSC_SCRAMBLE = - connector->display_info.hdmi.scdc.scrambling.low_rates; - - list_for_each_entry(preferred_mode, &connector->modes, head) { - /* Search for preferred mode */ - if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) { - native_mode_found = true; - break; - } - } - if (!native_mode_found) - preferred_mode = list_first_entry_or_null( - &connector->modes, - struct drm_display_mode, - head); - - mode_refresh = drm_mode_vrefresh(&mode); - - if (preferred_mode == NULL) { - /* - * This may not be an error, the use case is when we have no - * usermode calls to reset and set mode upon hotplug. In this - * case, we call set mode ourselves to restore the previous mode - * and the modelist may not be filled in time. - */ - drm_dbg_driver(dev, "No preferred mode found\n"); - } else if (aconnector) { - recalculate_timing = amdgpu_freesync_vid_mode && - is_freesync_video_mode(&mode, aconnector); - if (recalculate_timing) { - freesync_mode = get_highest_refresh_rate_mode(aconnector, false); - drm_mode_copy(&saved_mode, &mode); - saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio; - drm_mode_copy(&mode, freesync_mode); - mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio; - } else { - decide_crtc_timing_for_drm_display_mode( - &mode, preferred_mode, scale); - - preferred_refresh = drm_mode_vrefresh(preferred_mode); - } - } - - if (recalculate_timing) - drm_mode_set_crtcinfo(&saved_mode, 0); - - /* - * If scaling is enabled and refresh rate didn't change - * we copy the vic and polarities of the old timings - */ - if (!scale || mode_refresh != preferred_refresh) - fill_stream_properties_from_drm_display_mode( - stream, &mode, connector, con_state, NULL, - requested_bpc); - else - fill_stream_properties_from_drm_display_mode( - stream, &mode, connector, con_state, old_stream, - requested_bpc); - - /* The rest isn't needed for writeback connectors */ - if (!aconnector) - goto finish; - - if (aconnector->timing_changed) { - drm_dbg(aconnector->base.dev, - "overriding timing for automated test, bpc %d, changing to %d\n", - stream->timing.display_color_depth, - aconnector->timing_requested->display_color_depth); - stream->timing = *aconnector->timing_requested; - } - -#if defined(CONFIG_DRM_AMD_DC_FP) - /* SST DSC determination policy */ - update_dsc_caps(aconnector, sink, stream, &dsc_caps); - if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported) - apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps); -#endif - - update_stream_scaling_settings(dev, &mode, dm_state, stream); - - fill_audio_info( - &stream->audio_info, - connector, - sink); - - update_stream_signal(stream, sink); - - if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || - stream->signal == SIGNAL_TYPE_HDMI_FRL) - mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false); - - if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT || - stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST || - stream->signal == SIGNAL_TYPE_EDP) { - const struct dc_edid_caps *edid_caps; - unsigned int disable_colorimetry = 0; - - if (aconnector->dc_sink) { - edid_caps = &aconnector->dc_sink->edid_caps; - disable_colorimetry = edid_caps->panel_patch.disable_colorimetry; - } - - // - // should decide stream support vsc sdp colorimetry capability - // before building vsc info packet - // - stream->use_vsc_sdp_for_colorimetry = stream->link->dpcd_caps.dpcd_rev.raw >= 0x14 && - stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED && - !disable_colorimetry; - - if (stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22) - tf = TRANSFER_FUNC_GAMMA_22; - mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space, tf); - aconnector->sr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY; - - } -finish: - dc_sink_release(sink); - - return stream; -} - -/** - * amdgpu_dm_connector_poll - Poll a connector to see if it's connected to a display - * @aconnector: DM connector to poll (owns @base drm_connector and @dc_link) - * @force: if true, force polling even when DAC load detection was used - * - * Used for connectors that don't support HPD (hotplug detection) to - * periodically check whether the connector is connected to a display. - * - * When connection was determined via DAC load detection, we avoid - * re-running it on normal polls to prevent visible glitches, unless - * @force is set. - * - * Return: The probed connector status (connected/disconnected/unknown). - */ -static enum drm_connector_status -amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) -{ - struct drm_connector *connector = &aconnector->base; - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); - struct dc_link *link = aconnector->dc_link; - enum dc_connection_type conn_type = dc_connection_none; - enum drm_connector_status status = connector_status_disconnected; - - /* When we determined the connection using DAC load detection, - * do NOT poll the connector do detect disconnect because - * that would run DAC load detection again which can cause - * visible visual glitches. - * - * Only allow to poll such a connector again when forcing. - */ - if (!force && link->local_sink && link->type == dc_connection_analog_load) - return connector->status; - - mutex_lock(&aconnector->hpd_lock); - - if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) && - conn_type != dc_connection_none) { - mutex_lock(&adev->dm.dc_lock); - - /* Only call full link detection when a sink isn't created yet, - * ie. just when the display is plugged in, otherwise we risk flickering. - */ - if (link->local_sink || - dc_link_detect(link, DETECT_REASON_HPD)) - status = connector_status_connected; - - mutex_unlock(&adev->dm.dc_lock); - } - - if (connector->status != status) { - if (status == connector_status_disconnected) { - if (link->local_sink) - dc_sink_release(link->local_sink); - - link->local_sink = NULL; - link->dpcd_sink_count = 0; - link->type = dc_connection_none; - } - - amdgpu_dm_update_connector_after_detect(aconnector); - } - - mutex_unlock(&aconnector->hpd_lock); - return status; -} - -/** - * amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display - * - * A connector is considered connected when it has a sink that is not NULL. - * For connectors that support HPD (hotplug detection), the connection is - * handled in the HPD interrupt. - * For connectors that may not support HPD, such as analog connectors, - * DRM will call this function repeatedly to poll them. - * - * Notes: - * 1. This interface is NOT called in context of HPD irq. - * 2. This interface *is called* in context of user-mode ioctl. Which - * makes it a bad place for *any* MST-related activity. - * - * @connector: The DRM connector we are checking. We convert it to - * amdgpu_dm_connector so we can read the DC link and state. - * @force: If true, do a full detect again. This is used even when - * a lighter check would normally be used to avoid flicker. - * - * Return: The connector status (connected, disconnected, or unknown). - * - */ -static enum drm_connector_status -amdgpu_dm_connector_detect(struct drm_connector *connector, bool force) -{ - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - - update_subconnector_property(aconnector); - - if (aconnector->base.force == DRM_FORCE_ON || - aconnector->base.force == DRM_FORCE_ON_DIGITAL) - return connector_status_connected; - else if (aconnector->base.force == DRM_FORCE_OFF) - return connector_status_disconnected; - - /* Poll analog connectors and only when either - * disconnected or connected to an analog display. - */ - if (drm_kms_helper_is_poll_worker() && - dc_connector_supports_analog(aconnector->dc_link->link_id.id) && - (!aconnector->dc_sink || aconnector->dc_sink->edid_caps.analog)) - return amdgpu_dm_connector_poll(aconnector, force); - - return (aconnector->dc_sink ? connector_status_connected : - connector_status_disconnected); -} - -int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, - struct drm_connector_state *connector_state, - struct drm_property *property, - uint64_t val) -{ - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); - struct dm_connector_state *dm_old_state = - to_dm_connector_state(connector->state); - struct dm_connector_state *dm_new_state = - to_dm_connector_state(connector_state); - - int ret = -EINVAL; - - if (property == dev->mode_config.scaling_mode_property) { - enum amdgpu_rmx_type rmx_type; - - switch (val) { - case DRM_MODE_SCALE_CENTER: - rmx_type = RMX_CENTER; - break; - case DRM_MODE_SCALE_ASPECT: - rmx_type = RMX_ASPECT; - break; - case DRM_MODE_SCALE_FULLSCREEN: - rmx_type = RMX_FULL; - break; - case DRM_MODE_SCALE_NONE: - default: - rmx_type = RMX_OFF; - break; - } - - if (dm_old_state->scaling == rmx_type) - return 0; - - dm_new_state->scaling = rmx_type; - ret = 0; - } else if (property == adev->mode_info.underscan_hborder_property) { - dm_new_state->underscan_hborder = val; - ret = 0; - } else if (property == adev->mode_info.underscan_vborder_property) { - dm_new_state->underscan_vborder = val; - ret = 0; - } else if (property == adev->mode_info.underscan_property) { - dm_new_state->underscan_enable = val; - ret = 0; - } else if (property == adev->mode_info.abm_level_property) { - switch (val) { - case ABM_SYSFS_CONTROL: - dm_new_state->abm_sysfs_forbidden = false; - break; - case ABM_LEVEL_OFF: - dm_new_state->abm_sysfs_forbidden = true; - dm_new_state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE; - break; - default: - dm_new_state->abm_sysfs_forbidden = true; - dm_new_state->abm_level = val; - } - ret = 0; - } - - return ret; -} - -int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, - const struct drm_connector_state *state, - struct drm_property *property, - uint64_t *val) -{ - struct drm_device *dev = connector->dev; - struct amdgpu_device *adev = drm_to_adev(dev); - struct dm_connector_state *dm_state = - to_dm_connector_state(state); - int ret = -EINVAL; - - if (property == dev->mode_config.scaling_mode_property) { - switch (dm_state->scaling) { - case RMX_CENTER: - *val = DRM_MODE_SCALE_CENTER; - break; - case RMX_ASPECT: - *val = DRM_MODE_SCALE_ASPECT; - break; - case RMX_FULL: - *val = DRM_MODE_SCALE_FULLSCREEN; - break; - case RMX_OFF: - default: - *val = DRM_MODE_SCALE_NONE; - break; - } - ret = 0; - } else if (property == adev->mode_info.underscan_hborder_property) { - *val = dm_state->underscan_hborder; - ret = 0; - } else if (property == adev->mode_info.underscan_vborder_property) { - *val = dm_state->underscan_vborder; - ret = 0; - } else if (property == adev->mode_info.underscan_property) { - *val = dm_state->underscan_enable; - ret = 0; - } else if (property == adev->mode_info.abm_level_property) { - if (!dm_state->abm_sysfs_forbidden) - *val = ABM_SYSFS_CONTROL; - else - *val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ? - dm_state->abm_level : 0; - ret = 0; - } - - return ret; -} - -/** - * DOC: panel power savings - * - * The display manager allows you to set your desired **panel power savings** - * level (between 0-4, with 0 representing off), e.g. using the following:: - * - * # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings - * - * Modifying this value can have implications on color accuracy, so tread - * carefully. - */ - -static ssize_t panel_power_savings_show(struct device *device, - struct device_attribute *attr, - char *buf) -{ - struct drm_connector *connector = dev_get_drvdata(device); - struct drm_device *dev = connector->dev; - u8 val; - - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - val = to_dm_connector_state(connector->state)->abm_level == - ABM_LEVEL_IMMEDIATE_DISABLE ? 0 : - to_dm_connector_state(connector->state)->abm_level; - drm_modeset_unlock(&dev->mode_config.connection_mutex); - - return sysfs_emit(buf, "%u\n", val); -} - -static ssize_t panel_power_savings_store(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct drm_connector *connector = dev_get_drvdata(device); - struct drm_device *dev = connector->dev; - long val; - int ret; - - ret = kstrtol(buf, 0, &val); - - if (ret) - return ret; - - if (val < 0 || val > 4) - return -EINVAL; - - drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - if (to_dm_connector_state(connector->state)->abm_sysfs_forbidden) - ret = -EBUSY; - else - to_dm_connector_state(connector->state)->abm_level = val ?: - ABM_LEVEL_IMMEDIATE_DISABLE; - drm_modeset_unlock(&dev->mode_config.connection_mutex); - - if (ret) - return ret; - - drm_kms_helper_hotplug_event(dev); - - return count; -} - -static DEVICE_ATTR_RW(panel_power_savings); - -static struct attribute *amdgpu_attrs[] = { - &dev_attr_panel_power_savings.attr, - NULL -}; - -static const struct attribute_group amdgpu_group = { - .name = "amdgpu", - .attrs = amdgpu_attrs -}; - -static bool -amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *amdgpu_dm_connector) -{ - if (amdgpu_dm_abm_level >= 0) - return false; - - if (amdgpu_dm_connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) - return false; - - /* check for OLED panels */ - if (amdgpu_dm_connector->bl_idx >= 0) { - struct drm_device *drm = amdgpu_dm_connector->base.dev; - struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm; - struct amdgpu_dm_backlight_caps *caps; - - caps = &dm->backlight_caps[amdgpu_dm_connector->bl_idx]; - if (caps->aux_support) - return false; - } - - return true; -} - -static void amdgpu_dm_connector_unregister(struct drm_connector *connector) -{ - struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); - - if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) - sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group); - - cec_notifier_conn_unregister(amdgpu_dm_connector->notifier); - drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux); -} - -static void amdgpu_dm_connector_destroy(struct drm_connector *connector) -{ - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - struct amdgpu_device *adev = drm_to_adev(connector->dev); - struct amdgpu_display_manager *dm = &adev->dm; - - /* - * Call only if mst_mgr was initialized before since it's not done - * for all connector types. - */ - if (aconnector->mst_mgr.dev) - drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr); - - /* Cancel and flush any pending HDMI HPD debounce work */ - if (aconnector->hdmi_hpd_debounce_delay_ms) { - cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work); - if (aconnector->hdmi_prev_sink) { - dc_sink_release(aconnector->hdmi_prev_sink); - aconnector->hdmi_prev_sink = NULL; - } - } - - if (aconnector->bl_idx != -1) { - backlight_device_unregister(dm->backlight_dev[aconnector->bl_idx]); - dm->backlight_dev[aconnector->bl_idx] = NULL; - } - - if (aconnector->dc_em_sink) - dc_sink_release(aconnector->dc_em_sink); - aconnector->dc_em_sink = NULL; - if (aconnector->dc_sink) - dc_sink_release(aconnector->dc_sink); - aconnector->dc_sink = NULL; - - drm_dp_cec_unregister_connector(&aconnector->dm_dp_aux.aux); - drm_connector_unregister(connector); - drm_connector_cleanup(connector); - kfree(aconnector->dm_dp_aux.aux.name); - - kfree(connector); -} - -void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) -{ - struct dm_connector_state *state = - to_dm_connector_state(connector->state); - - if (connector->state) - __drm_atomic_helper_connector_destroy_state(connector->state); - - kfree(state); - - state = kzalloc_obj(*state); - - if (state) { - state->scaling = RMX_OFF; - state->underscan_enable = false; - state->underscan_hborder = 0; - state->underscan_vborder = 0; - state->base.max_requested_bpc = 8; - state->vcpi_slots = 0; - state->pbn = 0; - - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { - if (amdgpu_dm_abm_level <= 0) - state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE; - else - state->abm_level = amdgpu_dm_abm_level; - } - - __drm_atomic_helper_connector_reset(connector, &state->base); - } -} - -struct drm_connector_state * -amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector) -{ - struct dm_connector_state *state = - to_dm_connector_state(connector->state); - - struct dm_connector_state *new_state = - kmemdup(state, sizeof(*state), GFP_KERNEL); - - if (!new_state) - return NULL; - - __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); - - new_state->freesync_capable = state->freesync_capable; - new_state->abm_level = state->abm_level; - new_state->scaling = state->scaling; - new_state->underscan_enable = state->underscan_enable; - new_state->underscan_hborder = state->underscan_hborder; - new_state->underscan_vborder = state->underscan_vborder; - new_state->vcpi_slots = state->vcpi_slots; - new_state->pbn = state->pbn; - return &new_state->base; -} - -static int -amdgpu_dm_connector_late_register(struct drm_connector *connector) -{ - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - int r; - - if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) { - r = sysfs_create_group(&connector->kdev->kobj, - &amdgpu_group); - if (r) - return r; - } - - amdgpu_dm_register_backlight_device(amdgpu_dm_connector); - - if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || - (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { - amdgpu_dm_connector->dm_dp_aux.aux.dev = connector->kdev; - r = drm_dp_aux_register(&amdgpu_dm_connector->dm_dp_aux.aux); - if (r) - return r; - } - -#if defined(CONFIG_DEBUG_FS) - connector_debugfs_init(amdgpu_dm_connector); -#endif - - return 0; -} - -static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector) -{ - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - struct dc_link *dc_link = aconnector->dc_link; - struct dc_sink *dc_em_sink = aconnector->dc_em_sink; - const struct drm_edid *drm_edid; - struct i2c_adapter *ddc; - struct drm_device *dev = connector->dev; - - if (dc_link && dc_link->aux_mode) - ddc = &aconnector->dm_dp_aux.aux.ddc; - else - ddc = &aconnector->i2c->base; - - drm_edid = drm_edid_read_ddc(connector, ddc); - drm_edid_connector_update(connector, drm_edid); - if (!drm_edid) { - drm_err(dev, "No EDID found on connector: %s.\n", connector->name); - return; - } - - aconnector->drm_edid = drm_edid; - /* Update emulated (virtual) sink's EDID */ - if (dc_em_sink && dc_link) { - // FIXME: Get rid of drm_edid_raw() - const struct edid *edid = drm_edid_raw(drm_edid); - - memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps)); - memmove(dc_em_sink->dc_edid.raw_edid, edid, - (edid->extensions + 1) * EDID_LENGTH); - dm_helpers_parse_edid_caps( - dc_link, - &dc_em_sink->dc_edid, - &dc_em_sink->edid_caps); - } -} - -static const struct drm_connector_funcs amdgpu_dm_connector_funcs = { - .reset = amdgpu_dm_connector_funcs_reset, - .detect = amdgpu_dm_connector_detect, - .fill_modes = drm_helper_probe_single_connector_modes, - .destroy = amdgpu_dm_connector_destroy, - .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, - .atomic_set_property = amdgpu_dm_connector_atomic_set_property, - .atomic_get_property = amdgpu_dm_connector_atomic_get_property, - .late_register = amdgpu_dm_connector_late_register, - .early_unregister = amdgpu_dm_connector_unregister, - .force = amdgpu_dm_connector_funcs_force -}; - -static int get_modes(struct drm_connector *connector) -{ - return amdgpu_dm_connector_get_modes(connector); -} - -static void create_eml_sink(struct amdgpu_dm_connector *aconnector) -{ - struct drm_connector *connector = &aconnector->base; - struct dc_link *dc_link = aconnector->dc_link; - struct dc_sink_init_data init_params = { - .link = aconnector->dc_link, - .sink_signal = SIGNAL_TYPE_VIRTUAL - }; - const struct drm_edid *drm_edid; - const struct edid *edid; - struct i2c_adapter *ddc; - - if (dc_link && dc_link->aux_mode) - ddc = &aconnector->dm_dp_aux.aux.ddc; - else - ddc = &aconnector->i2c->base; - - drm_edid = drm_edid_read_ddc(connector, ddc); - drm_edid_connector_update(connector, drm_edid); - if (!drm_edid) { - drm_err(connector->dev, "No EDID found on connector: %s.\n", connector->name); - return; - } - - if (connector->display_info.is_hdmi) - init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; - - aconnector->drm_edid = drm_edid; - - edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw() - aconnector->dc_em_sink = dc_link_add_remote_sink( - aconnector->dc_link, - (uint8_t *)edid, - (edid->extensions + 1) * EDID_LENGTH, - &init_params); - - if (aconnector->base.force == DRM_FORCE_ON) { - aconnector->dc_sink = aconnector->dc_link->local_sink ? - aconnector->dc_link->local_sink : - aconnector->dc_em_sink; - if (aconnector->dc_sink) - dc_sink_retain(aconnector->dc_sink); - } -} - -static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector) -{ - struct dc_link *link = (struct dc_link *)aconnector->dc_link; - - /* - * In case of headless boot with force on for DP managed connector - * Those settings have to be != 0 to get initial modeset - */ - if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) { - link->verified_link_cap.lane_count = LANE_COUNT_FOUR; - link->verified_link_cap.link_rate = LINK_RATE_HIGH2; - } - - create_eml_sink(aconnector); -} - -static enum dc_status dm_validate_stream_and_context(struct dc *dc, - struct dc_stream_state *stream) -{ - enum dc_status dc_result = DC_ERROR_UNEXPECTED; - struct dc_plane_state *dc_plane_state = NULL; - struct dc_state *dc_state = NULL; - - if (!stream) - goto cleanup; - - dc_plane_state = dc_create_plane_state(dc); - if (!dc_plane_state) - goto cleanup; - - dc_state = dc_state_create(dc, NULL); - if (!dc_state) - goto cleanup; - - /* populate stream to plane */ - dc_plane_state->src_rect.height = stream->src.height; - dc_plane_state->src_rect.width = stream->src.width; - dc_plane_state->dst_rect.height = stream->src.height; - dc_plane_state->dst_rect.width = stream->src.width; - dc_plane_state->clip_rect.height = stream->src.height; - dc_plane_state->clip_rect.width = stream->src.width; - dc_plane_state->plane_size.surface_pitch = ((stream->src.width + 255) / 256) * 256; - dc_plane_state->plane_size.surface_size.height = stream->src.height; - dc_plane_state->plane_size.surface_size.width = stream->src.width; - dc_plane_state->plane_size.chroma_size.height = stream->src.height; - dc_plane_state->plane_size.chroma_size.width = stream->src.width; - dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888; - dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN; - dc_plane_state->rotation = ROTATION_ANGLE_0; - dc_plane_state->is_tiling_rotated = false; - dc_plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL; - - dc_result = dc_validate_stream(dc, stream); - if (dc_result == DC_OK) - dc_result = dc_validate_plane(dc, dc_plane_state); - - if (dc_result == DC_OK) - dc_result = dc_state_add_stream(dc, dc_state, stream); - - if (dc_result == DC_OK && !dc_state_add_plane( - dc, - stream, - dc_plane_state, - dc_state)) - dc_result = DC_FAIL_ATTACH_SURFACES; - - if (dc_result == DC_OK) - dc_result = dc_validate_global_state(dc, dc_state, DC_VALIDATE_MODE_ONLY); - -cleanup: - if (dc_state) - dc_state_release(dc_state); - - if (dc_plane_state) - dc_plane_state_release(dc_plane_state); - - return dc_result; -} - -static enum dc_status -dm_validate_stream_color_format(const struct drm_connector_state *drm_state, - const struct dc_stream_state *stream) -{ - enum dc_pixel_encoding encoding; - - if (!drm_state->color_format) - return DC_OK; - - switch (drm_state->color_format) { - case DRM_CONNECTOR_COLOR_FORMAT_AUTO: - case DRM_CONNECTOR_COLOR_FORMAT_RGB444: - encoding = PIXEL_ENCODING_RGB; - break; - case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: - encoding = PIXEL_ENCODING_YCBCR444; - break; - case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: - encoding = PIXEL_ENCODING_YCBCR422; - break; - case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: - encoding = PIXEL_ENCODING_YCBCR420; - break; - default: - encoding = PIXEL_ENCODING_UNDEFINED; - break; - } - - return encoding == stream->timing.pixel_encoding ? - DC_OK : DC_UNSUPPORTED_VALUE; -} - -struct dc_stream_state * -create_validate_stream_for_sink(struct drm_connector *connector, - const struct drm_display_mode *drm_mode, - const struct dm_connector_state *dm_state, - const struct dc_stream_state *old_stream) -{ - struct amdgpu_dm_connector *aconnector = NULL; - struct amdgpu_device *adev = drm_to_adev(connector->dev); - struct dc_stream_state *stream; - const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL; - int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8; - enum dc_status dc_result = DC_OK; - uint8_t bpc_limit = 6; - - if (!dm_state) - return NULL; - - if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) - aconnector = to_amdgpu_dm_connector(connector); - - if (aconnector && - (aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A || - aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_FRL || - aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)) - bpc_limit = 8; - - do { - drm_dbg_kms(connector->dev, "Trying with %d bpc\n", requested_bpc); - stream = create_stream_for_sink(connector, drm_mode, - dm_state, old_stream, - requested_bpc); - if (stream == NULL) { - drm_err(adev_to_drm(adev), "Failed to create stream for sink!\n"); - break; - } - - dc_result = dc_validate_stream(adev->dm.dc, stream); - - if (!aconnector) /* writeback connector */ - return stream; - - if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) - dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream); - - if (dc_result == DC_OK) - dc_result = dm_validate_stream_and_context(adev->dm.dc, stream); - - if (dc_result == DC_OK) - dc_result = dm_validate_stream_color_format(drm_state, stream); - - if (dc_result != DC_OK) { - drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n", - drm_mode->hdisplay, - drm_mode->vdisplay, - drm_mode->clock, - dc_pixel_encoding_to_str(stream->timing.pixel_encoding), - dc_color_depth_to_str(stream->timing.display_color_depth), - dc_status_to_str(dc_result)); - - dc_stream_release(stream); - stream = NULL; - requested_bpc -= 2; /* lower bpc to retry validation */ - } - - } while (stream == NULL && requested_bpc >= bpc_limit); - - switch (dc_result) { - /* - * If we failed to validate DP bandwidth stream with the requested RGB color depth, - * we try to fallback and configure in order: - * YUV422 (8bpc, 6bpc) - * YUV420 (8bpc, 6bpc) - */ - case DC_FAIL_ENC_VALIDATE: - case DC_EXCEED_DONGLE_CAP: - case DC_NO_DP_LINK_BANDWIDTH: - /* recursively entered twice and already tried both YUV422 and YUV420 */ - if (aconnector->force_yuv422_output && aconnector->force_yuv420_output) - break; - /* first failure; try YUV422 */ - if (!aconnector->force_yuv422_output) { - drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV422\n", - __func__, __LINE__, dc_result); - aconnector->force_yuv422_output = true; - /* recursively entered and YUV422 failed, try YUV420 */ - } else if (!aconnector->force_yuv420_output) { - drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV420\n", - __func__, __LINE__, dc_result); - aconnector->force_yuv420_output = true; - } - stream = create_validate_stream_for_sink(connector, drm_mode, - dm_state, old_stream); - aconnector->force_yuv422_output = false; - aconnector->force_yuv420_output = false; - break; - case DC_OK: - break; - default: - drm_dbg_kms(connector->dev, "%s:%d Unhandled validation failure %d\n", - __func__, __LINE__, dc_result); - break; - } - - return stream; -} - -enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector, - const struct drm_display_mode *mode) -{ - int result = MODE_ERROR; - struct dc_sink *dc_sink; - struct drm_display_mode *test_mode; - /* TODO: Unhardcode stream count */ - struct dc_stream_state *stream; - /* we always have an amdgpu_dm_connector here since we got - * here via the amdgpu_dm_connector_helper_funcs - */ - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - - if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || - (mode->flags & DRM_MODE_FLAG_DBLSCAN)) - return result; - - /* - * Only run this the first time mode_valid is called to initilialize - * EDID mgmt - */ - if (aconnector->base.force != DRM_FORCE_UNSPECIFIED && - !aconnector->dc_em_sink) - handle_edid_mgmt(aconnector); - - dc_sink = to_amdgpu_dm_connector(connector)->dc_sink; - - if (dc_sink == NULL && aconnector->base.force != DRM_FORCE_ON_DIGITAL && - aconnector->base.force != DRM_FORCE_ON) { - drm_err(connector->dev, "dc_sink is NULL!\n"); - goto fail; - } - - test_mode = drm_mode_duplicate(connector->dev, mode); - if (!test_mode) - goto fail; - - drm_mode_set_crtcinfo(test_mode, 0); - - stream = create_validate_stream_for_sink(connector, test_mode, - to_dm_connector_state(connector->state), - NULL); - drm_mode_destroy(connector->dev, test_mode); - if (stream) { - dc_stream_release(stream); - result = MODE_OK; - } - -fail: - /* TODO: error handling*/ - return result; -} - -static int fill_hdr_info_packet(const struct drm_connector_state *state, - struct dc_info_packet *out) -{ - struct hdmi_drm_infoframe frame; - unsigned char buf[30]; /* 26 + 4 */ - ssize_t len; - int ret, i; - - memset(out, 0, sizeof(*out)); - - if (!state->hdr_output_metadata) - return 0; - - ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, state); - if (ret) - return ret; - - len = hdmi_drm_infoframe_pack_only(&frame, buf, sizeof(buf)); - if (len < 0) - return (int)len; - - /* Static metadata is a fixed 26 bytes + 4 byte header. */ - if (len != 30) - return -EINVAL; - - /* Prepare the infopacket for DC. */ - switch (state->connector->connector_type) { - case DRM_MODE_CONNECTOR_HDMIA: - out->hb0 = 0x87; /* type */ - out->hb1 = 0x01; /* version */ - out->hb2 = 0x1A; /* length */ - out->sb[0] = buf[3]; /* checksum */ - i = 1; - break; - - case DRM_MODE_CONNECTOR_DisplayPort: - case DRM_MODE_CONNECTOR_eDP: - out->hb0 = 0x00; /* sdp id, zero */ - out->hb1 = 0x87; /* type */ - out->hb2 = 0x1D; /* payload len - 1 */ - out->hb3 = (0x13 << 2); /* sdp version */ - out->sb[0] = 0x01; /* version */ - out->sb[1] = 0x1A; /* length */ - i = 2; - break; - - default: - return -EINVAL; - } - - memcpy(&out->sb[i], &buf[4], 26); - out->valid = true; - - print_hex_dump(KERN_DEBUG, "HDR SB:", DUMP_PREFIX_NONE, 16, 1, out->sb, - sizeof(out->sb), false); - - return 0; -} - -static int -amdgpu_dm_connector_atomic_check(struct drm_connector *conn, - struct drm_atomic_commit *state) -{ - struct drm_connector_state *new_con_state = - drm_atomic_get_new_connector_state(state, conn); - struct drm_connector_state *old_con_state = - drm_atomic_get_old_connector_state(state, conn); - struct drm_crtc *crtc = new_con_state->crtc; - struct drm_crtc_state *new_crtc_state; - struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn); - int ret; - - if (WARN_ON(unlikely(!old_con_state || !new_con_state))) - return -EINVAL; - - trace_amdgpu_dm_connector_atomic_check(new_con_state); - - if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { - ret = drm_dp_mst_root_conn_atomic_check(new_con_state, &aconn->mst_mgr); - if (ret < 0) - return ret; - } - - if (!crtc) - return 0; - - if (new_con_state->privacy_screen_sw_state != old_con_state->privacy_screen_sw_state) { - new_crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(new_crtc_state)) - return PTR_ERR(new_crtc_state); - - new_crtc_state->mode_changed = true; - } - - if (new_con_state->colorspace != old_con_state->colorspace) { - new_crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(new_crtc_state)) - return PTR_ERR(new_crtc_state); - - new_crtc_state->mode_changed = true; - } - - if (new_con_state->content_type != old_con_state->content_type) { - new_crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(new_crtc_state)) - return PTR_ERR(new_crtc_state); - - new_crtc_state->mode_changed = true; - } - - if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) { - struct dc_info_packet hdr_infopacket; - - ret = fill_hdr_info_packet(new_con_state, &hdr_infopacket); - if (ret) - return ret; - - new_crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(new_crtc_state)) - return PTR_ERR(new_crtc_state); - - /* - * DC considers the stream backends changed if the - * static metadata changes. Forcing the modeset also - * gives a simple way for userspace to switch from - * 8bpc to 10bpc when setting the metadata to enter - * or exit HDR. - * - * Changing the static metadata after it's been - * set is permissible, however. So only force a - * modeset if we're entering or exiting HDR. - */ - new_crtc_state->mode_changed = new_crtc_state->mode_changed || - !old_con_state->hdr_output_metadata || - !new_con_state->hdr_output_metadata; - } - - return 0; -} - -static const struct drm_connector_helper_funcs -amdgpu_dm_connector_helper_funcs = { - /* - * If hotplugging a second bigger display in FB Con mode, bigger resolution - * modes will be filtered by drm_mode_validate_size(), and those modes - * are missing after user start lightdm. So we need to renew modes list. - * in get_modes call back, not just return the modes count - */ - .get_modes = get_modes, - .mode_valid = amdgpu_dm_connector_mode_valid, - .atomic_check = amdgpu_dm_connector_atomic_check, -}; - -static void dm_encoder_helper_disable(struct drm_encoder *encoder) -{ - -} - -int convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth) -{ - switch (display_color_depth) { - case COLOR_DEPTH_666: - return 6; - case COLOR_DEPTH_888: - return 8; - case COLOR_DEPTH_101010: - return 10; - case COLOR_DEPTH_121212: - return 12; - case COLOR_DEPTH_141414: - return 14; - case COLOR_DEPTH_161616: - return 16; - default: - break; - } - return 0; -} - -static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct drm_atomic_commit *state = crtc_state->state; - struct drm_connector *connector = conn_state->connector; - struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); - struct dm_connector_state *dm_new_connector_state = to_dm_connector_state(conn_state); - const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; - struct drm_dp_mst_topology_mgr *mst_mgr; - struct drm_dp_mst_port *mst_port; - struct drm_dp_mst_topology_state *mst_state; - enum dc_color_depth color_depth; - int clock, bpp = 0; - bool is_y420 = false; - - if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || - (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { - struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); - struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; - enum drm_mode_status result; - - result = drm_crtc_helper_mode_valid_fixed(encoder->crtc, adjusted_mode, native_mode); - if (result != MODE_OK && dm_new_connector_state->scaling == RMX_OFF) { - drm_dbg_driver(encoder->dev, - "mode %dx%d@%dHz is not native, enabling scaling\n", - adjusted_mode->hdisplay, adjusted_mode->vdisplay, - drm_mode_vrefresh(adjusted_mode)); - dm_new_connector_state->scaling = RMX_ASPECT; - } - return 0; - } - - if (!aconnector->mst_output_port) - return 0; - - mst_port = aconnector->mst_output_port; - mst_mgr = &aconnector->mst_root->mst_mgr; - - if (!crtc_state->connectors_changed && !crtc_state->mode_changed) - return 0; - - mst_state = drm_atomic_get_mst_topology_state(state, mst_mgr); - if (IS_ERR(mst_state)) - return PTR_ERR(mst_state); - - mst_state->pbn_div.full = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link); - - if (!state->duplicated) { - int max_bpc = conn_state->max_requested_bpc; - - is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) && - aconnector->force_yuv420_output; - color_depth = convert_color_depth_from_display_info(connector, - is_y420, - max_bpc); - bpp = convert_dc_color_depth_into_bpc(color_depth) * 3; - clock = adjusted_mode->clock; - dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4); - } - - dm_new_connector_state->vcpi_slots = - drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port, - dm_new_connector_state->pbn); - if (dm_new_connector_state->vcpi_slots < 0) { - drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); - return dm_new_connector_state->vcpi_slots; - } - return 0; -} - -const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = { - .disable = dm_encoder_helper_disable, - .atomic_check = dm_encoder_helper_atomic_check -}; - static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state, struct dc_state *dc_state, struct dsc_mst_fairness_vars *vars) @@ -8959,762 +3502,6 @@ static int dm_update_mst_vcpi_slots_for_dsc(struct drm_atomic_commit *state, return 0; } -static int to_drm_connector_type(enum signal_type st, uint32_t connector_id) -{ - switch (st) { - case SIGNAL_TYPE_HDMI_TYPE_A: - return DRM_MODE_CONNECTOR_HDMIA; - case SIGNAL_TYPE_EDP: - return DRM_MODE_CONNECTOR_eDP; - case SIGNAL_TYPE_LVDS: - return DRM_MODE_CONNECTOR_LVDS; - case SIGNAL_TYPE_RGB: - return DRM_MODE_CONNECTOR_VGA; - case SIGNAL_TYPE_DISPLAY_PORT: - case SIGNAL_TYPE_DISPLAY_PORT_MST: - /* External DP bridges have a different connector type. */ - if (connector_id == CONNECTOR_ID_VGA) - return DRM_MODE_CONNECTOR_VGA; - else if (connector_id == CONNECTOR_ID_LVDS) - return DRM_MODE_CONNECTOR_LVDS; - - return DRM_MODE_CONNECTOR_DisplayPort; - case SIGNAL_TYPE_DVI_DUAL_LINK: - case SIGNAL_TYPE_DVI_SINGLE_LINK: - if (connector_id == CONNECTOR_ID_SINGLE_LINK_DVII || - connector_id == CONNECTOR_ID_DUAL_LINK_DVII) - return DRM_MODE_CONNECTOR_DVII; - - return DRM_MODE_CONNECTOR_DVID; - case SIGNAL_TYPE_VIRTUAL: - return DRM_MODE_CONNECTOR_VIRTUAL; - - default: - return DRM_MODE_CONNECTOR_Unknown; - } -} - -static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector) -{ - struct drm_encoder *encoder; - - /* There is only one encoder per connector */ - drm_connector_for_each_possible_encoder(connector, encoder) - return encoder; - - return NULL; -} - -static void amdgpu_dm_get_native_mode(struct drm_connector *connector) -{ - struct drm_encoder *encoder; - struct amdgpu_encoder *amdgpu_encoder; - - encoder = amdgpu_dm_connector_to_encoder(connector); - - if (encoder == NULL) - return; - - amdgpu_encoder = to_amdgpu_encoder(encoder); - - amdgpu_encoder->native_mode.clock = 0; - - if (!list_empty(&connector->probed_modes)) { - struct drm_display_mode *preferred_mode = NULL; - - list_for_each_entry(preferred_mode, - &connector->probed_modes, - head) { - if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) - amdgpu_encoder->native_mode = *preferred_mode; - - break; - } - - } -} - -static struct drm_display_mode * -amdgpu_dm_create_common_mode(struct drm_encoder *encoder, - const char *name, - int hdisplay, int vdisplay) -{ - struct drm_device *dev = encoder->dev; - struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); - struct drm_display_mode *mode = NULL; - struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; - - mode = drm_mode_duplicate(dev, native_mode); - - if (mode == NULL) - return NULL; - - mode->hdisplay = hdisplay; - mode->vdisplay = vdisplay; - mode->type &= ~DRM_MODE_TYPE_PREFERRED; - strscpy(mode->name, name, DRM_DISPLAY_MODE_LEN); - - return mode; - -} - -static const struct amdgpu_dm_mode_size { - char name[DRM_DISPLAY_MODE_LEN]; - int w; - int h; -} common_modes[] = { - { "640x480", 640, 480}, - { "800x600", 800, 600}, - { "1024x768", 1024, 768}, - { "1280x720", 1280, 720}, - { "1280x800", 1280, 800}, - {"1280x1024", 1280, 1024}, - { "1440x900", 1440, 900}, - {"1680x1050", 1680, 1050}, - {"1600x1200", 1600, 1200}, - {"1920x1080", 1920, 1080}, - {"1920x1200", 1920, 1200} -}; - -static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder, - struct drm_connector *connector) -{ - struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); - struct drm_display_mode *mode = NULL; - struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - int i; - int n; - - if ((connector->connector_type != DRM_MODE_CONNECTOR_eDP) && - (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)) - return; - - n = ARRAY_SIZE(common_modes); - - for (i = 0; i < n; i++) { - struct drm_display_mode *curmode = NULL; - bool mode_existed = false; - - if (common_modes[i].w > native_mode->hdisplay || - common_modes[i].h > native_mode->vdisplay || - (common_modes[i].w == native_mode->hdisplay && - common_modes[i].h == native_mode->vdisplay)) - continue; - - list_for_each_entry(curmode, &connector->probed_modes, head) { - if (common_modes[i].w == curmode->hdisplay && - common_modes[i].h == curmode->vdisplay) { - mode_existed = true; - break; - } - } - - if (mode_existed) - continue; - - mode = amdgpu_dm_create_common_mode(encoder, - common_modes[i].name, common_modes[i].w, - common_modes[i].h); - if (!mode) - continue; - - drm_mode_probed_add(connector, mode); - amdgpu_dm_connector->num_modes++; - } -} - -static void amdgpu_set_panel_orientation(struct drm_connector *connector) -{ - struct drm_encoder *encoder; - struct amdgpu_encoder *amdgpu_encoder; - const struct drm_display_mode *native_mode; - - if (connector->connector_type != DRM_MODE_CONNECTOR_eDP && - connector->connector_type != DRM_MODE_CONNECTOR_LVDS) - return; - - mutex_lock(&connector->dev->mode_config.mutex); - amdgpu_dm_connector_get_modes(connector); - mutex_unlock(&connector->dev->mode_config.mutex); - - encoder = amdgpu_dm_connector_to_encoder(connector); - if (!encoder) - return; - - amdgpu_encoder = to_amdgpu_encoder(encoder); - - native_mode = &amdgpu_encoder->native_mode; - if (native_mode->hdisplay == 0 || native_mode->vdisplay == 0) - return; - - drm_connector_set_panel_orientation_with_quirk(connector, - DRM_MODE_PANEL_ORIENTATION_UNKNOWN, - native_mode->hdisplay, - native_mode->vdisplay); -} - -static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector, - const struct drm_edid *drm_edid) -{ - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - - if (drm_edid) { - /* empty probed_modes */ - INIT_LIST_HEAD(&connector->probed_modes); - amdgpu_dm_connector->num_modes = - drm_edid_connector_add_modes(connector); - - /* sorting the probed modes before calling function - * amdgpu_dm_get_native_mode() since EDID can have - * more than one preferred mode. The modes that are - * later in the probed mode list could be of higher - * and preferred resolution. For example, 3840x2160 - * resolution in base EDID preferred timing and 4096x2160 - * preferred resolution in DID extension block later. - */ - drm_mode_sort(&connector->probed_modes); - amdgpu_dm_get_native_mode(connector); - - /* Freesync capabilities are reset by calling - * drm_edid_connector_add_modes() and need to be - * restored here. - */ - amdgpu_dm_update_freesync_caps(connector, drm_edid, false); - } else { - amdgpu_dm_connector->num_modes = 0; - } -} - -static bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector, - struct drm_display_mode *mode) -{ - struct drm_display_mode *m; - - list_for_each_entry(m, &aconnector->base.probed_modes, head) { - if (drm_mode_equal(m, mode)) - return true; - } - - return false; -} - -static uint add_fs_modes(struct amdgpu_dm_connector *aconnector) -{ - const struct drm_display_mode *m; - struct drm_display_mode *new_mode; - uint i; - u32 new_modes_count = 0; - - /* Standard FPS values - * - * 23.976 - TV/NTSC - * 24 - Cinema - * 25 - TV/PAL - * 29.97 - TV/NTSC - * 30 - TV/NTSC - * 48 - Cinema HFR - * 50 - TV/PAL - * 60 - Commonly used - * 48,72,96,120 - Multiples of 24 - */ - static const u32 common_rates[] = { - 23976, 24000, 25000, 29970, 30000, - 48000, 50000, 60000, 72000, 96000, 120000 - }; - - /* - * Find mode with highest refresh rate with the same resolution - * as the preferred mode. Some monitors report a preferred mode - * with lower resolution than the highest refresh rate supported. - */ - - m = get_highest_refresh_rate_mode(aconnector, true); - if (!m) - return 0; - - for (i = 0; i < ARRAY_SIZE(common_rates); i++) { - u64 target_vtotal, target_vtotal_diff; - u64 num, den; - - if (drm_mode_vrefresh(m) * 1000 < common_rates[i]) - continue; - - if (common_rates[i] < aconnector->min_vfreq * 1000 || - common_rates[i] > aconnector->max_vfreq * 1000) - continue; - - num = (unsigned long long)m->clock * 1000 * 1000; - den = common_rates[i] * (unsigned long long)m->htotal; - target_vtotal = div_u64(num, den); - target_vtotal_diff = target_vtotal - m->vtotal; - - /* Check for illegal modes */ - if (m->vsync_start + target_vtotal_diff < m->vdisplay || - m->vsync_end + target_vtotal_diff < m->vsync_start || - m->vtotal + target_vtotal_diff < m->vsync_end) - continue; - - new_mode = drm_mode_duplicate(aconnector->base.dev, m); - if (!new_mode) - goto out; - - new_mode->vtotal += (u16)target_vtotal_diff; - new_mode->vsync_start += (u16)target_vtotal_diff; - new_mode->vsync_end += (u16)target_vtotal_diff; - new_mode->type &= ~DRM_MODE_TYPE_PREFERRED; - new_mode->type |= DRM_MODE_TYPE_DRIVER; - - if (!is_duplicate_mode(aconnector, new_mode)) { - drm_mode_probed_add(&aconnector->base, new_mode); - new_modes_count += 1; - } else - drm_mode_destroy(aconnector->base.dev, new_mode); - } - out: - return new_modes_count; -} - -static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector, - const struct drm_edid *drm_edid) -{ - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - - if (!(amdgpu_freesync_vid_mode && drm_edid)) - return; - - if (!amdgpu_dm_connector->dc_sink || !amdgpu_dm_connector->dc_link) - return; - - if (!dc_supports_vrr(amdgpu_dm_connector->dc_sink->ctx->dce_version)) - return; - - if (dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id) && - amdgpu_dm_connector->dc_sink->edid_caps.analog) - return; - - if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) - amdgpu_dm_connector->num_modes += - add_fs_modes(amdgpu_dm_connector); -} - -static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) -{ - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - struct dc_link *dc_link = amdgpu_dm_connector->dc_link; - struct drm_encoder *encoder; - const struct drm_edid *drm_edid = amdgpu_dm_connector->drm_edid; - struct dc_link_settings *verified_link_cap = &dc_link->verified_link_cap; - const struct dc *dc = dc_link->dc; - - encoder = amdgpu_dm_connector_to_encoder(connector); - - if (!drm_edid) { - amdgpu_dm_connector->num_modes = - drm_add_modes_noedid(connector, 640, 480); - if (dc->link_srv->dp_get_encoding_format(verified_link_cap) == DP_128b_132b_ENCODING) - amdgpu_dm_connector->num_modes += - drm_add_modes_noedid(connector, 1920, 1080); - - if (amdgpu_dm_connector->dc_sink && - amdgpu_dm_connector->dc_sink->edid_caps.analog && - dc_connector_supports_analog(dc_link->link_id.id)) { - /* Analog monitor connected by DAC load detection. - * Add common modes. It will be up to the user to select one that works. - */ - for (int i = 0; i < ARRAY_SIZE(common_modes); i++) - amdgpu_dm_connector->num_modes += drm_add_modes_noedid( - connector, common_modes[i].w, common_modes[i].h); - } - } else { - amdgpu_dm_connector_ddc_get_modes(connector, drm_edid); - if (encoder) - amdgpu_dm_connector_add_common_modes(encoder, connector); - amdgpu_dm_connector_add_freesync_modes(connector, drm_edid); - } - amdgpu_dm_fbc_init(connector); - - return amdgpu_dm_connector->num_modes; -} - -static const u32 supported_colorspaces = - BIT(DRM_MODE_COLORIMETRY_BT709_YCC) | - BIT(DRM_MODE_COLORIMETRY_OPRGB) | - BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) | - BIT(DRM_MODE_COLORIMETRY_BT2020_YCC); - -static const u32 supported_colorformats = - BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | - BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) | - BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | - BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420); - -void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, - struct amdgpu_dm_connector *aconnector, - int connector_type, - struct dc_link *link, - int link_index) -{ - struct amdgpu_device *adev = drm_to_adev(dm->ddev); - - /* - * Some of the properties below require access to state, like bpc. - * Allocate some default initial connector state with our reset helper. - */ - if (aconnector->base.funcs->reset) - aconnector->base.funcs->reset(&aconnector->base); - - aconnector->connector_id = link_index; - aconnector->bl_idx = -1; - aconnector->dc_link = link; - aconnector->base.interlace_allowed = false; - aconnector->base.doublescan_allowed = false; - aconnector->base.stereo_allowed = false; - aconnector->base.dpms = DRM_MODE_DPMS_OFF; - aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */ - aconnector->audio_inst = -1; - aconnector->pack_sdp_v1_3 = false; - aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE; - memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info)); - mutex_init(&aconnector->hpd_lock); - mutex_init(&aconnector->handle_mst_msg_ready); - - /* - * If HDMI HPD debounce delay is set, use the minimum between selected - * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS - */ - if (amdgpu_hdmi_hpd_debounce_delay_ms) { - aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms, - AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS); - INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, hdmi_hpd_debounce_work); - aconnector->hdmi_prev_sink = NULL; - } else { - aconnector->hdmi_hpd_debounce_delay_ms = 0; - } - - /* - * configure support HPD hot plug connector_>polled default value is 0 - * which means HPD hot plug not supported - */ - switch (connector_type) { - case DRM_MODE_CONNECTOR_HDMIA: - aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; - aconnector->base.ycbcr_420_allowed = - link->link_enc->features.hdmi_ycbcr420_supported ? true : false; - break; - case DRM_MODE_CONNECTOR_DisplayPort: - aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; - link->link_enc = link_enc_cfg_get_link_enc(link); - ASSERT(link->link_enc); - if (link->link_enc) - aconnector->base.ycbcr_420_allowed = - link->link_enc->features.dp_ycbcr420_supported ? true : false; - break; - case DRM_MODE_CONNECTOR_DVID: - aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; - break; - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_VGA: - aconnector->base.polled = - DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; - break; - default: - break; - } - - drm_object_attach_property(&aconnector->base.base, - dm->ddev->mode_config.scaling_mode_property, - DRM_MODE_SCALE_NONE); - - if (connector_type == DRM_MODE_CONNECTOR_HDMIA - || (connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root)) - drm_connector_attach_broadcast_rgb_property(&aconnector->base); - - drm_object_attach_property(&aconnector->base.base, - adev->mode_info.underscan_property, - UNDERSCAN_OFF); - drm_object_attach_property(&aconnector->base.base, - adev->mode_info.underscan_hborder_property, - 0); - drm_object_attach_property(&aconnector->base.base, - adev->mode_info.underscan_vborder_property, - 0); - - if (!aconnector->mst_root) - drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16); - - aconnector->base.state->max_bpc = 16; - aconnector->base.state->max_requested_bpc = aconnector->base.state->max_bpc; - - if (connector_type == DRM_MODE_CONNECTOR_HDMIA) { - /* Content Type is currently only implemented for HDMI. */ - drm_connector_attach_content_type_property(&aconnector->base); - } - - if (connector_type == DRM_MODE_CONNECTOR_HDMIA) { - if (!drm_mode_create_hdmi_colorspace_property(&aconnector->base, supported_colorspaces)) - drm_connector_attach_colorspace_property(&aconnector->base); - } else if ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root) || - connector_type == DRM_MODE_CONNECTOR_eDP) { - if (!drm_mode_create_dp_colorspace_property(&aconnector->base, supported_colorspaces)) - drm_connector_attach_colorspace_property(&aconnector->base); - } - - if (connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector_type == DRM_MODE_CONNECTOR_DisplayPort || - connector_type == DRM_MODE_CONNECTOR_eDP) { - drm_connector_attach_hdr_output_metadata_property(&aconnector->base); - - if (!aconnector->mst_root) { - drm_connector_attach_vrr_capable_property(&aconnector->base); - drm_connector_attach_color_format_property(&aconnector->base, - supported_colorformats); - } - - if (adev->dm.hdcp_workqueue) - drm_connector_attach_content_protection_property(&aconnector->base, true); - } - - if (connector_type == DRM_MODE_CONNECTOR_eDP) { - struct drm_privacy_screen *privacy_screen; - - drm_connector_attach_panel_type_property(&aconnector->base); - - privacy_screen = drm_privacy_screen_get(adev_to_drm(adev)->dev, NULL); - if (!IS_ERR(privacy_screen)) { - drm_connector_attach_privacy_screen_provider(&aconnector->base, - privacy_screen); - } else if (PTR_ERR(privacy_screen) != -ENODEV) { - drm_warn(adev_to_drm(adev), "Error getting privacy-screen\n"); - } - } -} - -static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) -{ - struct amdgpu_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); - struct ddc_service *ddc_service = i2c->ddc_service; - struct i2c_command cmd; - int i; - int result = -EIO; - - if (!ddc_service->ddc_pin) - return result; - - cmd.payloads = kzalloc_objs(struct i2c_payload, num); - - if (!cmd.payloads) - return result; - - cmd.number_of_payloads = num; - cmd.engine = I2C_COMMAND_ENGINE_DEFAULT; - cmd.speed = 100; - - for (i = 0; i < num; i++) { - cmd.payloads[i].write = !(msgs[i].flags & I2C_M_RD); - cmd.payloads[i].address = msgs[i].addr; - cmd.payloads[i].length = msgs[i].len; - cmd.payloads[i].data = msgs[i].buf; - } - - if (i2c->oem) { - if (dc_submit_i2c_oem( - ddc_service->ctx->dc, - &cmd)) - result = num; - } else { - if (dc_submit_i2c( - ddc_service->ctx->dc, - ddc_service->link->link_index, - &cmd)) - result = num; - } - - kfree(cmd.payloads); - return result; -} - -static u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm amdgpu_dm_i2c_algo = { - .master_xfer = amdgpu_dm_i2c_xfer, - .functionality = amdgpu_dm_i2c_func, -}; - -static struct amdgpu_i2c_adapter * -create_i2c(struct ddc_service *ddc_service, bool oem) -{ - struct amdgpu_device *adev = ddc_service->ctx->driver_context; - struct amdgpu_i2c_adapter *i2c; - - i2c = kzalloc_obj(struct amdgpu_i2c_adapter); - if (!i2c) - return NULL; - i2c->base.owner = THIS_MODULE; - i2c->base.dev.parent = &adev->pdev->dev; - i2c->base.algo = &amdgpu_dm_i2c_algo; - if (oem) - snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c OEM bus"); - else - snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d", - ddc_service->link->link_index); - i2c_set_adapdata(&i2c->base, i2c); - i2c->ddc_service = ddc_service; - i2c->oem = oem; - - return i2c; -} - -int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector) -{ - struct cec_connector_info conn_info; - struct drm_device *ddev = aconnector->base.dev; - struct device *hdmi_dev = ddev->dev; - - if (amdgpu_dc_debug_mask & DC_DISABLE_HDMI_CEC) { - drm_info(ddev, "HDMI-CEC feature masked\n"); - return -EINVAL; - } - - cec_fill_conn_info_from_drm(&conn_info, &aconnector->base); - aconnector->notifier = - cec_notifier_conn_register(hdmi_dev, NULL, &conn_info); - if (!aconnector->notifier) { - drm_err(ddev, "Failed to create cec notifier\n"); - return -ENOMEM; - } - - return 0; -} - -/* - * Note: this function assumes that dc_link_detect() was called for the - * dc_link which will be represented by this aconnector. - */ -static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, - struct amdgpu_dm_connector *aconnector, - u32 link_index, - struct amdgpu_encoder *aencoder) -{ - int res = 0; - int connector_type; - struct dc *dc = dm->dc; - struct dc_link *link = dc_get_link_at_index(dc, link_index); - struct amdgpu_i2c_adapter *i2c; - - /* Not needed for writeback connector */ - link->priv = aconnector; - - - i2c = create_i2c(link->ddc, false); - if (!i2c) { - drm_err(adev_to_drm(dm->adev), "Failed to create i2c adapter data\n"); - return -ENOMEM; - } - - aconnector->i2c = i2c; - res = devm_i2c_add_adapter(dm->adev->dev, &i2c->base); - - if (res) { - drm_err(adev_to_drm(dm->adev), "Failed to register hw i2c %d\n", link->link_index); - goto out_free; - } - - connector_type = to_drm_connector_type(link->connector_signal, link->link_id.id); - - res = drm_connector_init_with_ddc( - dm->ddev, - &aconnector->base, - &amdgpu_dm_connector_funcs, - connector_type, - &i2c->base); - - if (res) { - drm_err(adev_to_drm(dm->adev), "connector_init failed\n"); - aconnector->connector_id = -1; - goto out_free; - } - - drm_connector_helper_add( - &aconnector->base, - &amdgpu_dm_connector_helper_funcs); - - amdgpu_dm_connector_init_helper( - dm, - aconnector, - connector_type, - link, - link_index); - - drm_connector_attach_encoder( - &aconnector->base, &aencoder->base); - - if (connector_type == DRM_MODE_CONNECTOR_HDMIA || - connector_type == DRM_MODE_CONNECTOR_HDMIB) - amdgpu_dm_initialize_hdmi_connector(aconnector); - - if (dc_is_dp_signal(link->connector_signal)) - amdgpu_dm_initialize_dp_connector(dm, aconnector, link->link_index); - -out_free: - if (res) { - kfree(i2c); - aconnector->i2c = NULL; - } - return res; -} - -int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev) -{ - switch (adev->mode_info.num_crtc) { - case 1: - return 0x1; - case 2: - return 0x3; - case 3: - return 0x7; - case 4: - return 0xf; - case 5: - return 0x1f; - case 6: - default: - return 0x3f; - } -} - -static int amdgpu_dm_encoder_init(struct drm_device *dev, - struct amdgpu_encoder *aencoder, - uint32_t link_index) -{ - struct amdgpu_device *adev = drm_to_adev(dev); - - int res = drm_encoder_init(dev, - &aencoder->base, - &amdgpu_dm_encoder_funcs, - DRM_MODE_ENCODER_TMDS, - NULL); - - aencoder->base.possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev); - - if (!res) - aencoder->encoder_id = link_index; - else - aencoder->encoder_id = -1; - - drm_encoder_helper_add(&aencoder->base, &amdgpu_dm_encoder_helper_funcs); - - return res; -} - static void manage_dm_interrupts(struct amdgpu_device *adev, struct amdgpu_crtc *acrtc, struct dm_crtc_state *acrtc_state) @@ -9814,7 +3601,7 @@ static void dm_update_pflip_irq_state(struct amdgpu_device *adev, amdgpu_irq_update(adev, &adev->pageflip_irq, irq_type); } -static bool +STATIC_IFN_KUNIT bool is_scaling_state_different(const struct dm_connector_state *dm_state, const struct dm_connector_state *old_dm_state) { @@ -9831,6 +3618,7 @@ is_scaling_state_different(const struct dm_connector_state *dm_state, return true; return false; } +EXPORT_IF_KUNIT(is_scaling_state_different); static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state, struct drm_crtc_state *old_crtc_state, @@ -10414,14 +4202,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, continue; bundle->surface_updates[planes_count].surface = dc_plane; - if (new_pcrtc_state->color_mgmt_changed || new_plane_state->color_mgmt_changed) { + if (new_pcrtc_state->color_mgmt_changed) { bundle->surface_updates[planes_count].gamma = &dc_plane->gamma_correction; bundle->surface_updates[planes_count].in_transfer_func = &dc_plane->in_transfer_func; bundle->surface_updates[planes_count].gamut_remap_matrix = &dc_plane->gamut_remap_matrix; bundle->surface_updates[planes_count].hdr_mult = dc_plane->hdr_mult; - bundle->surface_updates[planes_count].func_shaper = &dc_plane->in_shaper_func; - bundle->surface_updates[planes_count].lut3d_func = &dc_plane->lut3d_func; - bundle->surface_updates[planes_count].blend_tf = &dc_plane->blend_tf; + bundle->surface_updates[planes_count].cm = &dc_plane->cm; } amdgpu_dm_plane_fill_dc_scaling_info(dm->adev, new_plane_state, @@ -10698,87 +4484,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state, kfree(bundle); } -static void amdgpu_dm_commit_audio(struct drm_device *dev, - struct drm_atomic_commit *state) -{ - struct amdgpu_device *adev = drm_to_adev(dev); - struct amdgpu_dm_connector *aconnector; - struct drm_connector *connector; - struct drm_connector_state *old_con_state, *new_con_state; - struct drm_crtc_state *new_crtc_state; - struct dm_crtc_state *new_dm_crtc_state; - const struct dc_stream_status *status; - int i, inst; - - /* Notify device removals. */ - for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { - if (old_con_state->crtc != new_con_state->crtc) { - /* CRTC changes require notification. */ - goto notify; - } - - if (!new_con_state->crtc) - continue; - - new_crtc_state = drm_atomic_get_new_crtc_state( - state, new_con_state->crtc); - - if (!new_crtc_state) - continue; - - if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) - continue; - -notify: - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - continue; - - aconnector = to_amdgpu_dm_connector(connector); - - mutex_lock(&adev->dm.audio_lock); - inst = aconnector->audio_inst; - aconnector->audio_inst = -1; - mutex_unlock(&adev->dm.audio_lock); - - amdgpu_dm_audio_eld_notify(adev, inst); - } - - /* Notify audio device additions. */ - for_each_new_connector_in_state(state, connector, new_con_state, i) { - if (!new_con_state->crtc) - continue; - - new_crtc_state = drm_atomic_get_new_crtc_state( - state, new_con_state->crtc); - - if (!new_crtc_state) - continue; - - if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) - continue; - - new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); - if (!new_dm_crtc_state->stream) - continue; - - status = dc_stream_get_status(new_dm_crtc_state->stream); - if (!status) - continue; - - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - continue; - - aconnector = to_amdgpu_dm_connector(connector); - - mutex_lock(&adev->dm.audio_lock); - inst = status->audio_inst; - aconnector->audio_inst = inst; - mutex_unlock(&adev->dm.audio_lock); - - amdgpu_dm_audio_eld_notify(adev, inst); - } -} - /* * amdgpu_dm_crtc_copy_transient_flags - copy mirrored flags from DRM to DC * @crtc_state: the DRM CRTC state @@ -10793,10 +4498,55 @@ static void amdgpu_dm_crtc_copy_transient_flags(struct drm_crtc_state *crtc_stat stream_state->mode_changed = drm_atomic_crtc_needs_modeset(crtc_state); } +/** + * amdgpu_dm_crtc_complete_writeback - finish a pending writeback job + * @acrtc: the CRTC whose pending writeback should be completed + * + * Clears the pending state, signals the writeback out fence and releases the + * vblank reference taken in dm_set_writeback() while the writeback was armed. + * The pending flag is tested and cleared under the writeback job lock, so this + * is safe to call concurrently from the completion vblank IRQ + * (dm_crtc_high_irq()) and from the writeback teardown path + * (dm_clear_writeback()); only the caller that observes the pending job + * performs the completion. + * + * Return: true if a pending writeback job was completed by this call. + */ +bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc) +{ + unsigned long flags; + bool pending; + + if (!acrtc->wb_conn) + return false; + + spin_lock_irqsave(&acrtc->wb_conn->job_lock, flags); + pending = acrtc->wb_pending; + acrtc->wb_pending = false; + spin_unlock_irqrestore(&acrtc->wb_conn->job_lock, flags); + + if (!pending) + return false; + + drm_writeback_signal_completion(acrtc->wb_conn, 0); + drm_crtc_vblank_put(&acrtc->base); + + return true; +} + static void dm_clear_writeback(struct amdgpu_display_manager *dm, + struct amdgpu_crtc *acrtc, struct dm_crtc_state *crtc_state) { dc_stream_remove_writeback(dm->dc, crtc_state->stream, 0); + + /* + * If the writeback is still pending when it is torn down (its + * completion vblank IRQ never fired), signal the out fence so a + * waiting client does not stall and release the vblank reference + * taken in dm_set_writeback(). + */ + amdgpu_dm_crtc_complete_writeback(acrtc); } /** @@ -10949,7 +4699,7 @@ static void amdgpu_dm_commit_streams(struct drm_atomic_commit *state, dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); - dm_clear_writeback(dm, dm_old_crtc_state); + dm_clear_writeback(dm, acrtc, dm_old_crtc_state); acrtc->wb_enabled = false; } @@ -11223,9 +4973,24 @@ static void dm_set_writeback(struct amdgpu_display_manager *dm, dc_stream_add_writeback(dm->dc, crtc_state->stream, wb_info); - acrtc->wb_pending = true; acrtc->wb_conn = wb_conn; drm_writeback_queue_job(wb_conn, new_con_state); + + /* + * Writeback completion is detected in the CRTC vblank IRQ + * (dm_crtc_high_irq()). Take a vblank reference so the vblank interrupt + * stays enabled while the writeback is pending; otherwise a + * writeback-only commit right after drm_crtc_vblank_on() (e.g. + * re-enabling a CRTC that was disabled) has no other vblank reference, + * the IRQ never fires and the out fence times out. The matching put + * happens once completion is signalled in dm_crtc_high_irq(), or when + * the writeback is torn down in dm_clear_writeback(). + * + * Arm wb_pending only after the reference is held so the completion IRQ + * cannot run its matching vblank_put before this get. + */ + WARN_ON(drm_crtc_vblank_get(&acrtc->base)); + acrtc->wb_pending = true; } static void amdgpu_dm_update_hdcp(struct drm_atomic_commit *state) @@ -11376,6 +5141,74 @@ static int amdgpu_dm_atomic_setup_commit(struct drm_atomic_commit *state) return 0; } +STATIC_IFN_KUNIT void set_multisync_trigger_params( + struct dc_stream_state *stream) +{ + struct dc_stream_state *master = NULL; + + if (stream->triggered_crtc_reset.enabled) { + master = stream->triggered_crtc_reset.event_source; + stream->triggered_crtc_reset.event = + master->timing.flags.VSYNC_POSITIVE_POLARITY ? + CRTC_EVENT_VSYNC_RISING : CRTC_EVENT_VSYNC_FALLING; + stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_PIXEL; + } +} +EXPORT_IF_KUNIT(set_multisync_trigger_params); + +STATIC_IFN_KUNIT void set_master_stream(struct dc_stream_state *stream_set[], + int stream_count) +{ + int j, highest_rfr = 0, master_stream = 0; + + for (j = 0; j < stream_count; j++) { + if (stream_set[j] && stream_set[j]->triggered_crtc_reset.enabled) { + int refresh_rate = 0; + + refresh_rate = (stream_set[j]->timing.pix_clk_100hz*100)/ + (stream_set[j]->timing.h_total*stream_set[j]->timing.v_total); + if (refresh_rate > highest_rfr) { + highest_rfr = refresh_rate; + master_stream = j; + } + } + } + for (j = 0; j < stream_count; j++) { + if (stream_set[j]) + stream_set[j]->triggered_crtc_reset.event_source = stream_set[master_stream]; + } +} +EXPORT_IF_KUNIT(set_master_stream); + +static void dm_enable_per_frame_crtc_master_sync(struct dc_state *context) +{ + int i = 0; + struct dc_stream_state *stream; + + if (context->stream_count < 2) + return; + for (i = 0; i < context->stream_count ; i++) { + if (!context->streams[i]) + continue; + /* + * TODO: add a function to read AMD VSDB bits and set + * crtc_sync_master.multi_sync_enabled flag + * For now it's set to false + */ + } + + set_master_stream(context->streams, context->stream_count); + + for (i = 0; i < context->stream_count ; i++) { + stream = context->streams[i]; + + if (!stream) + continue; + + set_multisync_trigger_params(stream); + } +} + /** * amdgpu_dm_atomic_commit_tail() - AMDgpu DM's commit tail implementation. * @state: The atomic state to commit @@ -11444,7 +5277,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) if ((new_con_state->hdmi.broadcast_rgb != old_con_state->hdmi.broadcast_rgb) && (dm_old_crtc_state->stream->output_color_space != - get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state))) + amdgpu_dm_get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state))) output_color_space_changed = true; abm_changed = dm_new_crtc_state->abm_level != @@ -11458,7 +5291,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) stream_update.stream = dm_new_crtc_state->stream; if (scaling_changed) { - update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode, + amdgpu_dm_update_stream_scaling_settings(dev, &dm_new_con_state->base.crtc->mode, dm_new_con_state, dm_new_crtc_state->stream); stream_update.src = dm_new_crtc_state->stream->src; @@ -11467,7 +5300,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) if (output_color_space_changed) { dm_new_crtc_state->stream->output_color_space - = get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state); + = amdgpu_dm_get_output_color_space(&dm_new_crtc_state->stream->timing, new_con_state); stream_update.output_color_space = &dm_new_crtc_state->stream->output_color_space; } @@ -11479,7 +5312,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) } if (hdr_changed) { - fill_hdr_info_packet(new_con_state, &hdr_packet); + amdgpu_dm_fill_hdr_info_packet(new_con_state, &hdr_packet); stream_update.hdr_static_metadata = &hdr_packet; } @@ -11687,104 +5520,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state) trace_amdgpu_dm_atomic_commit_tail_finish(state); } -static int dm_force_atomic_commit(struct drm_connector *connector) -{ - int ret = 0; - struct drm_device *ddev = connector->dev; - struct drm_atomic_commit *state = drm_atomic_commit_alloc(ddev); - struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc); - struct drm_plane *plane = disconnected_acrtc->base.primary; - struct drm_connector_state *conn_state; - struct drm_crtc_state *crtc_state; - struct drm_plane_state *plane_state; - - if (!state) - return -ENOMEM; - - state->acquire_ctx = ddev->mode_config.acquire_ctx; - - /* Construct an atomic state to restore previous display setting */ - - /* - * Attach connectors to drm_atomic_commit - */ - conn_state = drm_atomic_get_connector_state(state, connector); - - /* Check for error in getting connector state */ - if (IS_ERR(conn_state)) { - ret = PTR_ERR(conn_state); - goto out; - } - - /* Attach crtc to drm_atomic_commit*/ - crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base); - - /* Check for error in getting crtc state */ - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); - goto out; - } - - /* force a restore */ - crtc_state->mode_changed = true; - - /* Attach plane to drm_atomic_commit */ - plane_state = drm_atomic_get_plane_state(state, plane); - - /* Check for error in getting plane state */ - if (IS_ERR(plane_state)) { - ret = PTR_ERR(plane_state); - goto out; - } - - /* Call commit internally with the state we just constructed */ - ret = drm_atomic_commit(state); - -out: - drm_atomic_commit_put(state); - if (ret) - drm_err(ddev, "Restoring old state failed with %i\n", ret); - - return ret; -} - -/* - * This function handles all cases when set mode does not come upon hotplug. - * This includes when a display is unplugged then plugged back into the - * same port and when running without usermode desktop manager supprot - */ -void dm_restore_drm_connector_state(struct drm_device *dev, - struct drm_connector *connector) -{ - struct amdgpu_dm_connector *aconnector; - struct amdgpu_crtc *disconnected_acrtc; - struct dm_crtc_state *acrtc_state; - - if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) - return; - - aconnector = to_amdgpu_dm_connector(connector); - - if (!aconnector->dc_sink || !connector->state || !connector->encoder) - return; - - disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc); - if (!disconnected_acrtc) - return; - - acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state); - if (!acrtc_state->stream) - return; - - /* - * If the previous sink is not released and different from the current, - * we deduce we are in a state where we can not rely on usermode call - * to turn on the display, so we do it here - */ - if (acrtc_state->stream->sink != aconnector->dc_sink) - dm_force_atomic_commit(&aconnector->base); -} - /* * Grabs all modesetting locks to serialize against any blocking commits, * Waits for completion of all non blocking commits. @@ -11889,7 +5624,7 @@ static void reset_freesync_config_for_crtc( sizeof(new_crtc_state->vrr_infopacket)); } -static bool +STATIC_IFN_KUNIT bool is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state, struct drm_crtc_state *new_crtc_state) { @@ -11918,8 +5653,9 @@ is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state, return false; } +EXPORT_IF_KUNIT(is_timing_unchanged_for_freesync); -static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) +STATIC_IFN_KUNIT void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) { u64 num, den, res; struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base; @@ -11933,6 +5669,7 @@ static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) res = div_u64(num, den); dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = res; } +EXPORT_IF_KUNIT(set_freesync_fixed_config); static int dm_update_crtc_state(struct amdgpu_display_manager *dm, struct drm_atomic_commit *state, @@ -11986,7 +5723,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) goto skip_modeset; - new_stream = create_validate_stream_for_sink(connector, + new_stream = amdgpu_dm_create_validate_stream_for_sink(connector, &new_crtc_state->mode, dm_new_conn_state, dm_old_crtc_state->stream); @@ -12014,7 +5751,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, dm_new_crtc_state->abm_level = dm_new_conn_state->abm_level; - ret = fill_hdr_info_packet(drm_new_conn_state, + ret = amdgpu_dm_fill_hdr_info_packet(drm_new_conn_state, &new_stream->hdr_static_metadata); if (ret) goto fail; @@ -12083,11 +5820,11 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, goto skip_modeset; } else if (amdgpu_freesync_vid_mode && aconnector && - is_freesync_video_mode(&new_crtc_state->mode, + amdgpu_dm_is_freesync_video_mode(&new_crtc_state->mode, aconnector)) { struct drm_display_mode *high_mode; - high_mode = get_highest_refresh_rate_mode(aconnector, false); + high_mode = amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false); if (!drm_mode_equal(&new_crtc_state->mode, high_mode)) set_freesync_fixed_config(dm_new_crtc_state); } @@ -12179,7 +5916,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm, /* Scaling or underscan settings */ if (is_scaling_state_different(dm_old_conn_state, dm_new_conn_state) || drm_atomic_crtc_needs_modeset(new_crtc_state)) - update_stream_scaling_settings(adev_to_drm(adev), + amdgpu_dm_update_stream_scaling_settings(adev_to_drm(adev), &new_crtc_state->mode, dm_new_conn_state, dm_new_crtc_state->stream); /* ABM settings */ @@ -12275,10 +6012,6 @@ static bool should_reset_plane(struct drm_atomic_commit *state, if (new_crtc_state->color_mgmt_changed) return true; - /* Plane color pipeline or its colorop changes. */ - if (new_plane_state->color_mgmt_changed) - return true; - /* * On zpos change, planes need to be reordered by removing and re-adding * them one by one to the dc state, in order of descending zpos. @@ -12653,7 +6386,7 @@ static int dm_update_plane_state(struct dc *dc, /* Tell DC to do a full surface update every time there * is a plane change. Inefficient, but works for now. */ - dm_new_plane_state->dc_state->update_flags.bits.full_update = 1; + dm_new_plane_state->dc_state->update_bits.full_update = 1; *lock_and_validation_needed = true; } @@ -12672,8 +6405,8 @@ static int dm_update_plane_state(struct dc *dc, return ret; } -static void dm_get_oriented_plane_size(struct drm_plane_state *plane_state, - int *src_w, int *src_h) +STATIC_IFN_KUNIT void dm_get_oriented_plane_size(struct drm_plane_state *plane_state, + int *src_w, int *src_h) { switch (plane_state->rotation & DRM_MODE_ROTATE_MASK) { case DRM_MODE_ROTATE_90: @@ -12689,8 +6422,9 @@ static void dm_get_oriented_plane_size(struct drm_plane_state *plane_state, break; } } +EXPORT_IF_KUNIT(dm_get_oriented_plane_size); -static void +STATIC_IFN_KUNIT void dm_get_plane_scale(struct drm_plane_state *plane_state, int *out_plane_scale_w, int *out_plane_scale_h) { @@ -12700,6 +6434,7 @@ dm_get_plane_scale(struct drm_plane_state *plane_state, *out_plane_scale_w = plane_src_w ? plane_state->crtc_w * 1000 / plane_src_w : 0; *out_plane_scale_h = plane_src_h ? plane_state->crtc_h * 1000 / plane_src_h : 0; } +EXPORT_IF_KUNIT(dm_get_plane_scale); /* * The normalized_zpos value cannot be used by this iterator directly. It's only @@ -13560,373 +7295,6 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, return ret; } -static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm, - unsigned int offset, - unsigned int total_length, - u8 *data, - unsigned int length, - struct amdgpu_hdmi_vsdb_info *vsdb) -{ - bool res; - union dmub_rb_cmd cmd; - struct dmub_cmd_send_edid_cea *input; - struct dmub_cmd_edid_cea_output *output; - - if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES) - return false; - - memset(&cmd, 0, sizeof(cmd)); - - input = &cmd.edid_cea.data.input; - - cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA; - cmd.edid_cea.header.sub_type = 0; - cmd.edid_cea.header.payload_bytes = - sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header); - input->offset = offset; - input->length = length; - input->cea_total_length = total_length; - memcpy(input->payload, data, length); - - res = dc_wake_and_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); - if (!res) { - drm_err(adev_to_drm(dm->adev), "EDID CEA parser failed\n"); - return false; - } - - output = &cmd.edid_cea.data.output; - - if (output->type == DMUB_CMD__EDID_CEA_ACK) { - if (!output->ack.success) { - drm_err(adev_to_drm(dm->adev), "EDID CEA ack failed at offset %d\n", - output->ack.offset); - } - } else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) { - if (!output->amd_vsdb.vsdb_found) - return false; - - vsdb->freesync_supported = output->amd_vsdb.freesync_supported; - vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version; - vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate; - vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate; - vsdb->freesync_mccs_vcp_code = output->amd_vsdb.freesync_mccs_vcp_code; - } else { - drm_warn(adev_to_drm(dm->adev), "Unknown EDID CEA parser results\n"); - return false; - } - - return true; -} - -static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm, - u8 *edid_ext, int len, - struct amdgpu_hdmi_vsdb_info *vsdb_info) -{ - int i; - - /* send extension block to DMCU for parsing */ - for (i = 0; i < len; i += 8) { - bool res; - int offset; - - /* send 8 bytes a time */ - if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8)) - return false; - - if (i+8 == len) { - /* EDID block sent completed, expect result */ - int version, min_rate, max_rate; - - res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate); - if (res) { - /* amd vsdb found */ - vsdb_info->freesync_supported = 1; - vsdb_info->amd_vsdb_version = version; - vsdb_info->min_refresh_rate_hz = min_rate; - vsdb_info->max_refresh_rate_hz = max_rate; - /* Not enabled on DMCU*/ - vsdb_info->freesync_mccs_vcp_code = 0; - return true; - } - /* not amd vsdb */ - return false; - } - - /* check for ack*/ - res = dc_edid_parser_recv_cea_ack(dm->dc, &offset); - if (!res) - return false; - } - - return false; -} - -static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm, - u8 *edid_ext, int len, - struct amdgpu_hdmi_vsdb_info *vsdb_info) -{ - int i; - - /* send extension block to DMCU for parsing */ - for (i = 0; i < len; i += 8) { - /* send 8 bytes a time */ - if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info)) - return false; - } - - return vsdb_info->freesync_supported; -} - -static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, - u8 *edid_ext, int len, - struct amdgpu_hdmi_vsdb_info *vsdb_info) -{ - struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev); - bool ret; - - mutex_lock(&adev->dm.dc_lock); - if (adev->dm.dmub_srv) - ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info); - else - ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info); - mutex_unlock(&adev->dm.dc_lock); - return ret; -} - -static void parse_edid_displayid_vrr(struct drm_connector *connector, - const struct edid *edid) -{ - u8 *edid_ext = NULL; - int i; - int j = 0; - u16 min_vfreq; - u16 max_vfreq; - - if (!edid || !edid->extensions) - return; - - /* Find DisplayID extension */ - for (i = 0; i < edid->extensions; i++) { - edid_ext = (void *)(edid + (i + 1)); - if (edid_ext[0] == DISPLAYID_EXT) - break; - } - - if (i == edid->extensions) - return; - - while (j < EDID_LENGTH) { - /* Get dynamic video timing range from DisplayID if available */ - if (EDID_LENGTH - j > 13 && edid_ext[j] == 0x25 && - (edid_ext[j+1] & 0xFE) == 0 && (edid_ext[j+2] == 9)) { - min_vfreq = edid_ext[j+9]; - if (edid_ext[j+1] & 7) - max_vfreq = edid_ext[j+10] + ((edid_ext[j+11] & 3) << 8); - else - max_vfreq = edid_ext[j+10]; - - if (max_vfreq && min_vfreq) { - connector->display_info.monitor_range.max_vfreq = max_vfreq; - connector->display_info.monitor_range.min_vfreq = min_vfreq; - - return; - } - } - j++; - } -} - -static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector, - struct amdgpu_hdmi_vsdb_info *vsdb_info) -{ - struct drm_connector *connector = &aconnector->base; - - vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode; - vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version; - - return connector->display_info.amd_vsdb.version != 0; -} - -static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, - const struct edid *edid, - struct amdgpu_hdmi_vsdb_info *vsdb_info) -{ - u8 *edid_ext = NULL; - int i; - bool valid_vsdb_found = false; - - /*----- drm_find_cea_extension() -----*/ - /* No EDID or EDID extensions */ - if (edid == NULL || edid->extensions == 0) - return -ENODEV; - - /* Find CEA extension */ - for (i = 0; i < edid->extensions; i++) { - edid_ext = (uint8_t *)edid + EDID_LENGTH * (i + 1); - if (edid_ext[0] == CEA_EXT) - break; - } - - if (i == edid->extensions) - return -ENODEV; - - /*----- cea_db_offsets() -----*/ - if (edid_ext[0] != CEA_EXT) - return -ENODEV; - - valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info); - - return valid_vsdb_found ? i : -ENODEV; -} - -/** - * amdgpu_dm_update_freesync_caps - Update Freesync capabilities - * - * @connector: Connector to query. - * @drm_edid: DRM EDID from monitor - * @do_mccs: Controls whether MCCS (Monitor Control Command Set) over - * DDC (Display Data Channel) transactions are performed. When true, - * the driver queries the monitor to get or update additional FreeSync - * capability information. When false, these transactions are skipped. - * - * Amdgpu supports Freesync in DP and HDMI displays, and it is required to keep - * track of some of the display information in the internal data struct used by - * amdgpu_dm. This function checks which type of connector we need to set the - * FreeSync parameters. - */ -void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - const struct drm_edid *drm_edid, bool do_mccs) -{ - int i = 0; - struct amdgpu_dm_connector *amdgpu_dm_connector = - to_amdgpu_dm_connector(connector); - struct dm_connector_state *dm_con_state = NULL; - struct dc_sink *sink; - struct amdgpu_device *adev = drm_to_adev(connector->dev); - struct amdgpu_hdmi_vsdb_info vsdb_info = {0}; - const struct edid *edid; - bool freesync_capable = false; - enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE; - - if (!connector->state) { - drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__); - goto update; - } - - sink = amdgpu_dm_connector->dc_sink ? - amdgpu_dm_connector->dc_sink : - amdgpu_dm_connector->dc_em_sink; - - drm_edid_connector_update(connector, drm_edid); - - if (!drm_edid || !sink) { - dm_con_state = to_dm_connector_state(connector->state); - - amdgpu_dm_connector->min_vfreq = 0; - amdgpu_dm_connector->max_vfreq = 0; - freesync_capable = false; - - goto update; - } - - dm_con_state = to_dm_connector_state(connector->state); - - if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version)) - goto update; - - edid = drm_edid_raw(drm_edid); // FIXME: Get rid of drm_edid_raw() - - /* Some eDP panels only have the refresh rate range info in DisplayID */ - if ((connector->display_info.monitor_range.min_vfreq == 0 || - connector->display_info.monitor_range.max_vfreq == 0)) - parse_edid_displayid_vrr(connector, edid); - - if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT || - sink->sink_signal == SIGNAL_TYPE_EDP)) { - if (amdgpu_dm_connector->dc_link && - amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) { - amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq; - amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq; - if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) - freesync_capable = true; - } - - get_amd_vsdb(amdgpu_dm_connector, &vsdb_info); - - if (vsdb_info.replay_mode) { - amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode; - amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version; - amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP; - } - - } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) { - i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); - if (i >= 0) { - amdgpu_dm_connector->vsdb_info = vsdb_info; - sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code; - - if (vsdb_info.freesync_supported) { - amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; - amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; - if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) - freesync_capable = true; - - connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; - connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; - } - } - } - - if (amdgpu_dm_connector->dc_link) - as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link); - - if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) { - i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); - if (i >= 0) { - amdgpu_dm_connector->vsdb_info = vsdb_info; - sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code; - - if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) { - amdgpu_dm_connector->pack_sdp_v1_3 = true; - amdgpu_dm_connector->as_type = as_type; - - amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; - amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; - if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) - freesync_capable = true; - - connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; - connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; - } - } - } - - /* Handle MCCS */ - if (do_mccs) { - dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); - - if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported) - freesync_capable = false; - - if (sink->mccs_caps.freesync_supported && freesync_capable) - dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); - } - -update: - if (dm_con_state) - dm_con_state->freesync_capable = freesync_capable; - - if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable && - amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) { - amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported = false; - amdgpu_dm_connector->dc_link->replay_settings.replay_feature_enabled = false; - } - - if (connector->vrr_capable_property) - drm_connector_set_vrr_capable_property(connector, - freesync_capable); -} - void amdgpu_dm_trigger_timing_sync(struct drm_device *dev) { struct amdgpu_device *adev = drm_to_adev(dev); @@ -13946,12 +7314,6 @@ void amdgpu_dm_trigger_timing_sync(struct drm_device *dev) mutex_unlock(&adev->dm.dc_lock); } -static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc) -{ - if (dc->ctx->dmub_srv && !dc->ctx->dmub_srv->idle_exit_counter) - dc_exit_ips_for_hw_access(dc); -} - void dm_write_reg_func(const struct dc_context *ctx, uint32_t address, u32 value, const char *func_name) { @@ -13980,13 +7342,6 @@ uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address, } #endif - if (ctx->dmub_srv && - ctx->dmub_srv->reg_helper_offload.gather_in_progress && - !ctx->dmub_srv->reg_helper_offload.should_burst_write) { - ASSERT(false); - return 0; - } - amdgpu_dm_exit_ips_for_hw_access(ctx->dc); value = cgs_read_register(ctx->cgs_device, address); @@ -13996,179 +7351,6 @@ uint32_t dm_read_reg_func(const struct dc_context *ctx, uint32_t address, return value; } -int amdgpu_dm_process_dmub_aux_transfer_sync( - struct dc_context *ctx, - unsigned int link_index, - struct aux_payload *payload, - enum aux_return_code_type *operation_result) -{ - struct amdgpu_device *adev = ctx->driver_context; - struct dmub_notification *p_notify = adev->dm.dmub_notify; - int ret = -1; - - mutex_lock(&adev->dm.dpia_aux_lock); - if (!dc_process_dmub_aux_transfer_async(ctx->dc, link_index, payload)) { - *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE; - goto out; - } - - if (!wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) { - drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!"); - *operation_result = AUX_RET_ERROR_TIMEOUT; - goto out; - } - - if (p_notify->result != AUX_RET_SUCCESS) { - /* - * Transient states before tunneling is enabled could - * lead to this error. We can ignore this for now. - */ - if (p_notify->result == AUX_RET_ERROR_PROTOCOL_ERROR) { - drm_warn(adev_to_drm(adev), "DPIA AUX failed on 0x%x(%d), error %d\n", - payload->address, payload->length, - p_notify->result); - } - *operation_result = p_notify->result; - goto out; - } - - payload->reply[0] = adev->dm.dmub_notify->aux_reply.command & 0xF; - if (adev->dm.dmub_notify->aux_reply.command & 0xF0) - /* The reply is stored in the top nibble of the command. */ - payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF; - - /*write req may receive a byte indicating partially written number as well*/ - if (p_notify->aux_reply.length) - memcpy(payload->data, p_notify->aux_reply.data, - p_notify->aux_reply.length); - - /* success */ - ret = p_notify->aux_reply.length; - *operation_result = p_notify->result; -out: - reinit_completion(&adev->dm.dmub_aux_transfer_done); - mutex_unlock(&adev->dm.dpia_aux_lock); - return ret; -} - -static void abort_fused_io( - struct dc_context *ctx, - const struct dmub_cmd_fused_request *request -) -{ - union dmub_rb_cmd command = { 0 }; - struct dmub_rb_cmd_fused_io *io = &command.fused_io; - - io->header.type = DMUB_CMD__FUSED_IO; - io->header.sub_type = DMUB_CMD__FUSED_IO_ABORT; - io->header.payload_bytes = sizeof(*io) - sizeof(io->header); - io->request = *request; - dm_execute_dmub_cmd(ctx, &command, DM_DMUB_WAIT_TYPE_NO_WAIT); -} - -static bool execute_fused_io( - struct amdgpu_device *dev, - struct dc_context *ctx, - union dmub_rb_cmd *commands, - uint8_t count, - uint32_t timeout_us -) -{ - const uint8_t ddc_line = commands[0].fused_io.request.u.aux.ddc_line; - - if (ddc_line >= ARRAY_SIZE(dev->dm.fused_io)) - return false; - - struct fused_io_sync *sync = &dev->dm.fused_io[ddc_line]; - struct dmub_rb_cmd_fused_io *first = &commands[0].fused_io; - const bool result = dm_execute_dmub_cmd_list(ctx, count, commands, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) - && first->header.ret_status - && first->request.status == FUSED_REQUEST_STATUS_SUCCESS; - - if (!result) - return false; - - while (wait_for_completion_timeout(&sync->replied, usecs_to_jiffies(timeout_us))) { - reinit_completion(&sync->replied); - - struct dmub_cmd_fused_request *reply = (struct dmub_cmd_fused_request *) sync->reply_data; - - static_assert(sizeof(*reply) <= sizeof(sync->reply_data), "Size mismatch"); - - if (reply->identifier == first->request.identifier) { - first->request = *reply; - return true; - } - } - - reinit_completion(&sync->replied); - first->request.status = FUSED_REQUEST_STATUS_TIMEOUT; - abort_fused_io(ctx, &first->request); - return false; -} - -bool amdgpu_dm_execute_fused_io( - struct amdgpu_device *dev, - struct dc_link *link, - union dmub_rb_cmd *commands, - uint8_t count, - uint32_t timeout_us) -{ - struct amdgpu_display_manager *dm = &dev->dm; - - mutex_lock(&dm->dpia_aux_lock); - - const bool result = execute_fused_io(dev, link->ctx, commands, count, timeout_us); - - mutex_unlock(&dm->dpia_aux_lock); - return result; -} - -int amdgpu_dm_process_dmub_set_config_sync( - struct dc_context *ctx, - unsigned int link_index, - struct set_config_cmd_payload *payload, - enum set_config_status *operation_result) -{ - struct amdgpu_device *adev = ctx->driver_context; - bool is_cmd_complete; - int ret; - - mutex_lock(&adev->dm.dpia_aux_lock); - is_cmd_complete = dc_process_dmub_set_config_async(ctx->dc, - link_index, payload, adev->dm.dmub_notify); - - if (is_cmd_complete || wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) { - ret = 0; - *operation_result = adev->dm.dmub_notify->sc_status; - } else { - drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!"); - ret = -1; - *operation_result = SET_CONFIG_UNKNOWN_ERROR; - } - - if (!is_cmd_complete) - reinit_completion(&adev->dm.dmub_aux_transfer_done); - mutex_unlock(&adev->dm.dpia_aux_lock); - return ret; -} - -bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type) -{ - struct amdgpu_device *adev = ctx->driver_context; - - guard(spinlock_irqsave)(&adev->dm.dmub_lock); - return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type); -} - -bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type) -{ - struct amdgpu_device *adev = ctx->driver_context; - - guard(spinlock_irqsave)(&adev->dm.dmub_lock); - return dc_dmub_srv_cmd_run_list(ctx->dmub_srv, count, cmd, wait_type); -} - void dm_acpi_process_phy_transition_interlock( const struct dc_context *ctx, struct dm_process_phy_transition_init_params process_phy_transition_init_params) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index dd199e0b7922..91affbdb2d6c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -877,6 +877,9 @@ struct amdgpu_dm_connector { unsigned int hdmi_hpd_debounce_delay_ms; struct delayed_work hdmi_hpd_debounce_work; struct dc_sink *hdmi_prev_sink; + + /* HDMI compliance automation */ + bool hdmi_comp_auto; }; static inline void amdgpu_dm_set_mst_status(uint8_t *status, @@ -1061,35 +1064,7 @@ struct dm_connector_state { #define to_dm_connector_state(x)\ container_of((x), struct dm_connector_state, base) -void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector); -struct drm_connector_state * -amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector); -int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, - struct drm_connector_state *state, - struct drm_property *property, - uint64_t val); - -int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, - const struct drm_connector_state *state, - struct drm_property *property, - uint64_t *val); - -int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev); - -void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, - struct amdgpu_dm_connector *aconnector, - int connector_type, - struct dc_link *link, - int link_index); - -enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector, - const struct drm_display_mode *mode); - -void dm_restore_drm_connector_state(struct drm_device *dev, - struct drm_connector *connector); - -void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, - const struct drm_edid *drm_edid, bool do_mccs); +#include "amdgpu_dm_connector.h" void amdgpu_dm_trigger_timing_sync(struct drm_device *dev); @@ -1113,14 +1088,9 @@ int amdgpu_dm_update_plane_color_mgmt(struct dm_crtc_state *crtc, struct drm_plane_state *plane_state, struct dc_plane_state *dc_plane_state); -void amdgpu_dm_update_connector_after_detect( - struct amdgpu_dm_connector *aconnector); - void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *info, struct dc_edid_caps *edid_caps); -extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs; - int amdgpu_dm_process_dmub_aux_transfer_sync(struct dc_context *ctx, unsigned int link_index, struct aux_payload *payload, enum aux_return_code_type *operation_result); @@ -1135,20 +1105,9 @@ bool amdgpu_dm_execute_fused_io( int amdgpu_dm_process_dmub_set_config_sync(struct dc_context *ctx, unsigned int link_index, struct set_config_cmd_payload *payload, enum set_config_status *operation_result); -struct dc_stream_state * - create_validate_stream_for_sink(struct drm_connector *connector, - const struct drm_display_mode *drm_mode, - const struct dm_connector_state *dm_state, - const struct dc_stream_state *old_stream); - int dm_atomic_get_state(struct drm_atomic_commit *state, struct dm_atomic_state **dm_state); -struct drm_connector * -amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_commit *state, - struct drm_crtc *crtc); - -int convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth); struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev); void *dm_allocate_gpu_mem(struct amdgpu_device *adev, @@ -1161,11 +1120,33 @@ void dm_free_gpu_mem(struct amdgpu_device *adev, bool amdgpu_dm_is_headless(struct amdgpu_device *adev); -void hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector); -void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector); -int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector); +bool amdgpu_dm_crtc_complete_writeback(struct amdgpu_crtc *acrtc); void retrieve_dmi_info(struct amdgpu_display_manager *dm); -void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, int bl_idx); +void amdgpu_dm_emulated_link_detect(struct dc_link *link); +void amdgpu_dm_apply_delay_after_dpcd_poweroff(struct amdgpu_device *adev, + struct dc_sink *sink); + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +int dm_plane_layer_index_cmp(const void *a, const void *b); +int fill_plane_color_attributes(const struct drm_plane_state *plane_state, + const enum surface_pixel_format format, + enum dc_color_space *color_space); +bool modereset_required(struct drm_crtc_state *crtc_state); +void dm_get_oriented_plane_size(struct drm_plane_state *plane_state, + int *src_w, int *src_h); +void dm_get_plane_scale(struct drm_plane_state *plane_state, + int *out_plane_scale_w, int *out_plane_scale_h); +bool is_scaling_state_different(const struct dm_connector_state *dm_state, + const struct dm_connector_state *old_dm_state); +bool is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state, + struct drm_crtc_state *new_crtc_state); +void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state); +bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state, + struct dm_crtc_state *new_state); +void set_multisync_trigger_params(struct dc_stream_state *stream); +void set_master_stream(struct dc_stream_state *stream_set[], int stream_count); +#endif + #endif /* __AMDGPU_DM_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c new file mode 100644 index 000000000000..13c9a9d145ba --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.c @@ -0,0 +1,323 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + */ + +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_audio.h" +#include "amdgpu_dm_kunit_helpers.h" +#include "dc.h" + +#include +#include +#include +#include +#include +#include + +#include "dc/inc/core_types.h" + +static int amdgpu_dm_audio_component_get_eld(struct device *kdev, int port, + int pipe, bool *enabled, + unsigned char *buf, int max_bytes) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = drm_to_adev(dev); + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + struct amdgpu_dm_connector *aconnector; + int ret = 0; + + *enabled = false; + + mutex_lock(&adev->dm.audio_lock); + + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->audio_inst != port) + continue; + + *enabled = true; + mutex_lock(&connector->eld_mutex); + ret = drm_eld_size(connector->eld); + memcpy(buf, connector->eld, min(max_bytes, ret)); + mutex_unlock(&connector->eld_mutex); + + break; + } + drm_connector_list_iter_end(&conn_iter); + + mutex_unlock(&adev->dm.audio_lock); + + drm_dbg_kms(adev_to_drm(adev), "Get ELD : idx=%d ret=%d en=%d\n", port, ret, *enabled); + + return ret; +} + +static const struct drm_audio_component_ops amdgpu_dm_audio_component_ops = { + .get_eld = amdgpu_dm_audio_component_get_eld, +}; + +STATIC_IFN_KUNIT int amdgpu_dm_audio_component_bind(struct device *kdev, + struct device *hda_kdev, void *data) +{ + struct drm_device *dev = dev_get_drvdata(kdev); + struct amdgpu_device *adev = drm_to_adev(dev); + struct drm_audio_component *acomp = data; + + acomp->ops = &amdgpu_dm_audio_component_ops; + acomp->dev = kdev; + adev->dm.audio_component = acomp; + + return 0; +} +EXPORT_IF_KUNIT(amdgpu_dm_audio_component_bind); + +STATIC_IFN_KUNIT void amdgpu_dm_audio_component_unbind(struct device *kdev, + struct device *hda_kdev, void *data) +{ + struct amdgpu_device *adev = drm_to_adev(dev_get_drvdata(kdev)); + struct drm_audio_component *acomp = data; + + acomp->ops = NULL; + acomp->dev = NULL; + adev->dm.audio_component = NULL; +} +EXPORT_IF_KUNIT(amdgpu_dm_audio_component_unbind); + +static const struct component_ops amdgpu_dm_audio_component_bind_ops = { + .bind = amdgpu_dm_audio_component_bind, + .unbind = amdgpu_dm_audio_component_unbind, +}; + +int amdgpu_dm_audio_init(struct amdgpu_device *adev) +{ + int i, ret; + + if (!amdgpu_audio) + return 0; + + adev->mode_info.audio.enabled = true; + + adev->mode_info.audio.num_pins = adev->dm.dc->res_pool->audio_count; + + for (i = 0; i < adev->mode_info.audio.num_pins; i++) { + adev->mode_info.audio.pin[i].channels = -1; + adev->mode_info.audio.pin[i].rate = -1; + adev->mode_info.audio.pin[i].bits_per_sample = -1; + adev->mode_info.audio.pin[i].status_bits = 0; + adev->mode_info.audio.pin[i].category_code = 0; + adev->mode_info.audio.pin[i].connected = false; + adev->mode_info.audio.pin[i].id = + adev->dm.dc->res_pool->audios[i]->inst; + adev->mode_info.audio.pin[i].offset = 0; + } + + ret = component_add(adev->dev, &amdgpu_dm_audio_component_bind_ops); + if (ret < 0) + return ret; + + adev->dm.audio_registered = true; + + return 0; +} +EXPORT_IF_KUNIT(amdgpu_dm_audio_init); + +void amdgpu_dm_audio_fini(struct amdgpu_device *adev) +{ + if (!amdgpu_audio) + return; + + if (!adev->mode_info.audio.enabled) + return; + + if (adev->dm.audio_registered) { + component_del(adev->dev, &amdgpu_dm_audio_component_bind_ops); + adev->dm.audio_registered = false; + } + + /* TODO: Disable audio? */ + + adev->mode_info.audio.enabled = false; +} +EXPORT_IF_KUNIT(amdgpu_dm_audio_fini); + +STATIC_IFN_KUNIT void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin) +{ + struct drm_audio_component *acomp = adev->dm.audio_component; + + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) { + drm_dbg_kms(adev_to_drm(adev), "Notify ELD: %d\n", pin); + + acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, + pin, -1); + } +} +EXPORT_IF_KUNIT(amdgpu_dm_audio_eld_notify); + +void amdgpu_dm_fill_audio_info(struct audio_info *audio_info, + const struct drm_connector *drm_connector, + const struct dc_sink *dc_sink) +{ + int i = 0; + int cea_revision = 0; + const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps; + + audio_info->manufacture_id = edid_caps->manufacturer_id; + audio_info->product_id = edid_caps->product_id; + + cea_revision = drm_connector->display_info.cea_rev; + + strscpy(audio_info->display_name, + edid_caps->display_name, + AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS); + + if (cea_revision >= 3) { + audio_info->mode_count = edid_caps->audio_mode_count; + + for (i = 0; i < audio_info->mode_count; ++i) { + audio_info->modes[i].format_code = + (enum audio_format_code) + (edid_caps->audio_modes[i].format_code); + audio_info->modes[i].channel_count = + edid_caps->audio_modes[i].channel_count; + audio_info->modes[i].sample_rates.all = + edid_caps->audio_modes[i].sample_rate; + audio_info->modes[i].sample_size = + edid_caps->audio_modes[i].sample_size; + } + } + + audio_info->flags.all = edid_caps->speaker_flags; + + /* TODO: We only check for the progressive mode, check for interlace mode too */ + if (drm_connector->latency_present[0]) { + audio_info->video_latency = drm_connector->video_latency[0]; + audio_info->audio_latency = drm_connector->audio_latency[0]; + } + + /* TODO: For DP, video and audio latency should be calculated from DPCD caps */ + +} +EXPORT_IF_KUNIT(amdgpu_dm_fill_audio_info); + +void amdgpu_dm_commit_audio(struct drm_device *dev, + struct drm_atomic_commit *state) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + struct amdgpu_dm_connector *aconnector; + struct drm_connector *connector; + struct drm_connector_state *old_con_state, *new_con_state; + struct drm_crtc_state *new_crtc_state; + struct dm_crtc_state *new_dm_crtc_state; + const struct dc_stream_status *status; + int i, inst; + + /* Notify device removals. */ + for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { + if (old_con_state->crtc != new_con_state->crtc) { + /* CRTC changes require notification. */ + goto notify; + } + + if (!new_con_state->crtc) + continue; + + new_crtc_state = drm_atomic_get_new_crtc_state( + state, new_con_state->crtc); + + if (!new_crtc_state) + continue; + + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + continue; + +notify: + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + + mutex_lock(&adev->dm.audio_lock); + inst = aconnector->audio_inst; + aconnector->audio_inst = -1; + mutex_unlock(&adev->dm.audio_lock); + + amdgpu_dm_audio_eld_notify(adev, inst); + } + + /* Notify audio device additions. */ + for_each_new_connector_in_state(state, connector, new_con_state, i) { + if (!new_con_state->crtc) + continue; + + new_crtc_state = drm_atomic_get_new_crtc_state( + state, new_con_state->crtc); + + if (!new_crtc_state) + continue; + + if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) + continue; + + new_dm_crtc_state = to_dm_crtc_state(new_crtc_state); + if (!new_dm_crtc_state->stream) + continue; + + status = dc_stream_get_status(new_dm_crtc_state->stream); + if (!status) + continue; + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + + mutex_lock(&adev->dm.audio_lock); + inst = status->audio_inst; + aconnector->audio_inst = inst; + mutex_unlock(&adev->dm.audio_lock); + + amdgpu_dm_audio_eld_notify(adev, inst); + } +} + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +int amdgpu_dm_audio_get_param(void) +{ + return amdgpu_audio; +} +EXPORT_IF_KUNIT(amdgpu_dm_audio_get_param); + +void amdgpu_dm_audio_set_param(int val) +{ + amdgpu_audio = val; +} +EXPORT_IF_KUNIT(amdgpu_dm_audio_set_param); +#endif diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.h similarity index 50% rename from drivers/gpu/drm/amd/display/modules/power/power_helpers.c rename to drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.h index bf0c5901b4ee..7acfc5ef69b3 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_audio.h @@ -1,4 +1,6 @@ -/* Copyright 2018 Advanced Micro Devices, Inc. +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -19,21 +21,36 @@ * OTHER DEALINGS IN THE SOFTWARE. * * Authors: AMD - * */ -#include "power_helpers.h" -#include "dc/inc/hw/dmcu.h" -#include "dc/inc/hw/abm.h" -#include "dc.h" -#include "core_types.h" -#include "dmub_cmd.h" +#ifndef __AMDGPU_DM_AUDIO_H__ +#define __AMDGPU_DM_AUDIO_H__ -#define DIV_ROUNDUP(a, b) (((a)+((b)/2))/(b)) -#define bswap16_based_on_endian(big_endian, value) \ - ((big_endian) ? cpu_to_be16(value) : cpu_to_le16(value)) +struct amdgpu_device; +struct drm_device; +struct drm_atomic_state; +struct drm_connector; +struct audio_info; +struct dc_sink; -bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream) -{ - return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal); -} +int amdgpu_dm_audio_init(struct amdgpu_device *adev); +void amdgpu_dm_audio_fini(struct amdgpu_device *adev); +void amdgpu_dm_commit_audio(struct drm_device *dev, + struct drm_atomic_commit *state); +void amdgpu_dm_fill_audio_info(struct audio_info *audio_info, + const struct drm_connector *drm_connector, + const struct dc_sink *dc_sink); + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +struct device; + +int amdgpu_dm_audio_component_bind(struct device *kdev, + struct device *hda_kdev, void *data); +void amdgpu_dm_audio_component_unbind(struct device *kdev, + struct device *hda_kdev, void *data); +void amdgpu_dm_audio_eld_notify(struct amdgpu_device *adev, int pin); +int amdgpu_dm_audio_get_param(void); +void amdgpu_dm_audio_set_param(int val); +#endif + +#endif /* __AMDGPU_DM_AUDIO_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c new file mode 100644 index 000000000000..33f4be403a65 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c @@ -0,0 +1,726 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + */ + +#include "dc.h" +#include "dc/dc_dmub_srv.h" +#include "dc/dc_state.h" +#include "dc/dc_stat.h" + +#include "amdgpu.h" +#include "amdgpu_display.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_backlight.h" +#include "amdgpu_dm_psr.h" +#include "amdgpu_dm_replay.h" +#include "amdgpu_atombios.h" + +#include "modules/inc/mod_power.h" + +#include +#include +#include +#include + +#include + +#include "amdgpu_dm_trace.h" +#include "amd_shared.h" +#include "amdgpu_dm_kunit_helpers.h" + +void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, + int bl_idx) +{ + struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[bl_idx]; + + if (caps->caps_valid) + return; + +#if defined(CONFIG_ACPI) + amdgpu_acpi_get_backlight_caps(caps); + + /* validate the firmware value is sane */ + if (caps->caps_valid) { + int spread = caps->max_input_signal - caps->min_input_signal; + + if (caps->max_input_signal > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || + caps->min_input_signal < 0 || + spread > AMDGPU_DM_DEFAULT_MAX_BACKLIGHT || + spread < AMDGPU_DM_MIN_SPREAD) { + drm_dbg_kms(adev_to_drm(dm->adev), "DM: Invalid backlight caps: min=%d, max=%d\n", + caps->min_input_signal, caps->max_input_signal); + caps->caps_valid = false; + } + } +#else + if (caps->aux_support) + return; +#endif + if (!caps->caps_valid) { + caps->min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps->max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps->ac_level = caps->dc_level = 50; + caps->caps_valid = true; + } +} +EXPORT_IF_KUNIT(amdgpu_dm_update_backlight_caps); + +STATIC_IFN_KUNIT +int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps, + unsigned int *min, unsigned int *max) +{ + if (!caps) + return 0; + + if (caps->aux_support) { + /* Firmware limits are in nits, DC API wants millinits. */ + *max = 1000 * caps->aux_max_input_signal; + *min = 1000 * caps->aux_min_input_signal; + } else { + /* Firmware limits are 8-bit, PWM control is 16-bit. */ + *max = 0x101 * caps->max_input_signal; + *min = 0x101 * caps->min_input_signal; + } + return 1; +} +EXPORT_IF_KUNIT(get_brightness_range); + +/* Rescale from [min..max] to [0..AMDGPU_MAX_BL_LEVEL] */ +static inline u32 scale_input_to_fw(int min, int max, u64 input) +{ + return DIV_ROUND_CLOSEST_ULL(input * AMDGPU_MAX_BL_LEVEL, max - min); +} + +/* Rescale from [0..AMDGPU_MAX_BL_LEVEL] to [min..max] */ +static inline u32 scale_fw_to_input(int min, int max, u64 input) +{ + return min + DIV_ROUND_CLOSEST_ULL(input * (max - min), AMDGPU_MAX_BL_LEVEL); +} + +STATIC_IFN_KUNIT +void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps, + unsigned int min, unsigned int max, + uint32_t *user_brightness) +{ + u32 brightness = scale_input_to_fw(min, max, *user_brightness); + u8 lower_signal, upper_signal, upper_lum, lower_lum, lum; + int left, right; + + if (amdgpu_dc_debug_mask & DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE) + return; + + if (!caps->data_points) + return; + + /* + * Handle the case where brightness is below the first data point + * Interpolate between (0,0) and (first_signal, first_lum) + */ + if (brightness < caps->luminance_data[0].input_signal) { + lum = DIV_ROUND_CLOSEST(caps->luminance_data[0].luminance * brightness, + caps->luminance_data[0].input_signal); + goto scale; + } + + left = 0; + right = caps->data_points - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + u8 signal = caps->luminance_data[mid].input_signal; + + /* Exact match found */ + if (signal == brightness) { + lum = caps->luminance_data[mid].luminance; + goto scale; + } + + if (signal < brightness) + left = mid + 1; + else + right = mid - 1; + } + + /* verify bound */ + if (left >= caps->data_points) + left = caps->data_points - 1; + + /* At this point, left > right */ + lower_signal = caps->luminance_data[right].input_signal; + upper_signal = caps->luminance_data[left].input_signal; + lower_lum = caps->luminance_data[right].luminance; + upper_lum = caps->luminance_data[left].luminance; + + /* interpolate */ + if (right == left || !lower_lum) + lum = upper_lum; + else + lum = lower_lum + DIV_ROUND_CLOSEST((upper_lum - lower_lum) * + (brightness - lower_signal), + upper_signal - lower_signal); +scale: + *user_brightness = scale_fw_to_input(min, max, + DIV_ROUND_CLOSEST(lum * brightness, 101)); +} + +EXPORT_IF_KUNIT(convert_custom_brightness); + +STATIC_IFN_KUNIT +u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps, + uint32_t brightness) +{ + unsigned int min, max; + + if (!get_brightness_range(caps, &min, &max)) + return brightness; + + convert_custom_brightness(caps, min, max, &brightness); + + /* Rescale 0..max to min..max */ + return min + DIV_ROUND_CLOSEST_ULL((u64)(max - min) * brightness, max); +} + +EXPORT_IF_KUNIT(convert_brightness_from_user); + +STATIC_IFN_KUNIT +u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps, + uint32_t brightness) +{ + unsigned int min, max; + + if (!get_brightness_range(caps, &min, &max)) + return brightness; + + if (brightness < min) + return 0; + /* Rescale min..max to 0..max */ + return DIV_ROUND_CLOSEST_ULL((u64)max * (brightness - min), + max - min); +} +EXPORT_IF_KUNIT(convert_brightness_to_user); + +static struct dc_stream_state *dm_find_stream_with_link( + struct amdgpu_display_manager *dm, + struct dc_link *link) +{ + struct dc_state *cur_dc_state = dm->dc->current_state; + struct dc_stream_state *stream = NULL; + int i; + + for (i = 0; i < cur_dc_state->stream_count; i++) { + stream = cur_dc_state->streams[i]; + if (stream->link == link) + return stream; + } + + return NULL; +} + +STATIC_IFN_KUNIT +int amdgpu_dm_backlight_get_device_index(struct amdgpu_display_manager *dm, + struct backlight_device *bd) +{ + int i; + + for (i = 0; i < dm->num_of_edps; i++) { + if (bd == dm->backlight_dev[i]) + return i; + } + + return 0; +} +EXPORT_IF_KUNIT(amdgpu_dm_backlight_get_device_index); + +void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, + int bl_idx, + u32 user_brightness) +{ + struct amdgpu_dm_backlight_caps *caps; + struct dc_link *link; + u32 brightness = 0; + bool rc = false, reallow_idle = false; + struct drm_connector *connector; + struct dc_stream_state *stream; + unsigned int min, max; + + list_for_each_entry(connector, &dm->ddev->mode_config.connector_list, head) { + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + + if (aconnector->bl_idx != bl_idx) + continue; + + /* if connector is off, save the brightness for next time it's on */ + if (!aconnector->base.encoder) { + dm->brightness[bl_idx] = user_brightness; + dm->actual_brightness[bl_idx] = 0; + return; + } + } + + amdgpu_dm_update_backlight_caps(dm, bl_idx); + caps = &dm->backlight_caps[bl_idx]; + + dm->brightness[bl_idx] = user_brightness; + /* update scratch register */ + if (bl_idx == 0) + amdgpu_atombios_scratch_regs_set_backlight_level(dm->adev, dm->brightness[bl_idx]); + brightness = convert_brightness_from_user(caps, dm->brightness[bl_idx]); + link = (struct dc_link *)dm->backlight_link[bl_idx]; + + /* Apply brightness quirk */ + if (caps->brightness_mask) + brightness |= caps->brightness_mask; + + if (trace_amdgpu_dm_brightness_enabled()) { + trace_amdgpu_dm_brightness(__builtin_return_address(0), + user_brightness, + brightness, + caps->aux_support, + power_supply_is_system_supplied() > 0); + } + + stream = dm_find_stream_with_link(dm, link); + if (!stream) + return; + + mutex_lock(&dm->dc_lock); + if (dm->dc->caps.ips_support && dm->dc->ctx->dmub_srv->idle_allowed) { + dc_allow_idle_optimizations(dm->dc, false); + reallow_idle = true; + } + + if (caps->aux_support) { + rc = mod_power_set_backlight_nits(dm->power_module, stream, brightness, + AUX_BL_DEFAULT_TRANSITION_TIME_MS, false, true); + } else { + /* power module uses millipercent */ + get_brightness_range(caps, &min, &max); + brightness = DIV_ROUND_CLOSEST(brightness * 100, (max - min)) * 1000; + rc = mod_power_set_backlight_percent(dm->power_module, stream, + brightness, 0, false); + } + + /* + * Some kms clients create a ramped backlight transition effect + * by rapidly changing the backlight. Yet we must wait on dmcub + * fw to exit psr/replay before programming backlight. To + * prevent lag, keep disable psr/replay and let the next atomic + * flip clear the event. + * + * ToDo: use ISM to handle rapidly backlight change + * + * Rapidly backlight change is similar to rapidly cursor events, + * which is now handled by ISM. ISM can delay the event until system + * is really idle, so we may use ISM to handle backlight change as well. + */ + amdgpu_dm_psr_set_event(dm, stream, true, + psr_event_hw_programming, true); + amdgpu_dm_replay_set_event(dm, stream, true, + replay_event_hw_programming, true); + + if (dm->dc->caps.ips_support && reallow_idle) + dc_allow_idle_optimizations(dm->dc, true); + + mutex_unlock(&dm->dc_lock); + + if (rc) + dm->actual_brightness[bl_idx] = user_brightness; +} + +static int amdgpu_dm_backlight_update_status(struct backlight_device *bd) +{ + struct amdgpu_display_manager *dm = bl_get_data(bd); + int i = amdgpu_dm_backlight_get_device_index(dm, bd); + + amdgpu_dm_backlight_set_level(dm, i, bd->props.brightness); + + return 0; +} + +static u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm, + int bl_idx) +{ + int ret; + struct amdgpu_dm_backlight_caps caps; + struct dc_link *link = (struct dc_link *)dm->backlight_link[bl_idx]; + + amdgpu_dm_update_backlight_caps(dm, bl_idx); + caps = dm->backlight_caps[bl_idx]; + + if (caps.aux_support) { + u32 avg, peak; + + if (!dc_link_get_backlight_level_nits(link, &avg, &peak)) + return dm->brightness[bl_idx]; + return convert_brightness_to_user(&caps, avg); + } + + ret = dc_link_get_backlight_level(link); + + if (ret == DC_ERROR_UNEXPECTED) + return dm->brightness[bl_idx]; + + return convert_brightness_to_user(&caps, ret); +} + +static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd) +{ + struct amdgpu_display_manager *dm = bl_get_data(bd); + int i = amdgpu_dm_backlight_get_device_index(dm, bd); + + return amdgpu_dm_backlight_get_level(dm, i); +} + +static const struct backlight_ops amdgpu_dm_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = amdgpu_dm_backlight_get_brightness, + .update_status = amdgpu_dm_backlight_update_status, +}; + +STATIC_IFN_KUNIT +void amdgpu_dm_backlight_fill_props(const struct amdgpu_dm_backlight_caps *caps, + bool is_system_supplied, + bool custom_curve_enabled, + struct backlight_properties *props) +{ + unsigned int min, max; + + if (get_brightness_range(caps, &min, &max)) { + if (is_system_supplied) + props->brightness = DIV_ROUND_CLOSEST((max - min) * caps->ac_level, + 100); + else + props->brightness = DIV_ROUND_CLOSEST((max - min) * caps->dc_level, + 100); + props->max_brightness = max - min; + } else { + props->brightness = MAX_BACKLIGHT_LEVEL; + props->max_brightness = MAX_BACKLIGHT_LEVEL; + } + + if (caps && caps->data_points && custom_curve_enabled) + props->scale = BACKLIGHT_SCALE_NON_LINEAR; + else + props->scale = BACKLIGHT_SCALE_LINEAR; + props->type = BACKLIGHT_RAW; +} +EXPORT_IF_KUNIT(amdgpu_dm_backlight_fill_props); + +void +amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector) +{ + struct drm_device *drm = aconnector->base.dev; + struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm; + struct backlight_properties props = { 0 }; + struct amdgpu_dm_backlight_caps *caps; + char bl_name[16]; + int real_brightness; + int init_brightness; + + if (aconnector->bl_idx == -1) + return; + + if (!acpi_video_backlight_use_native()) { + drm_info(drm, "Skipping amdgpu DM backlight registration\n"); + /* Try registering an ACPI video backlight device instead. */ + acpi_video_register_backlight(); + return; + } + + caps = &dm->backlight_caps[aconnector->bl_idx]; + amdgpu_dm_backlight_fill_props(caps, power_supply_is_system_supplied() > 0, + !(amdgpu_dc_debug_mask & + DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE), + &props); + drm_dbg(drm, "Backlight caps: max_brightness: %d, ac %d, dc %d\n", + props.max_brightness, caps->ac_level, caps->dc_level); + + init_brightness = props.brightness; + + if (props.scale == BACKLIGHT_SCALE_NON_LINEAR) + drm_info(drm, "Using custom brightness curve\n"); + + snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d", + drm->primary->index + aconnector->bl_idx); + + dm->backlight_dev[aconnector->bl_idx] = + backlight_device_register(bl_name, aconnector->base.kdev, dm, + &amdgpu_dm_backlight_ops, &props); + dm->brightness[aconnector->bl_idx] = props.brightness; + + if (IS_ERR(dm->backlight_dev[aconnector->bl_idx])) { + drm_err(drm, "DM: Backlight registration failed!\n"); + dm->backlight_dev[aconnector->bl_idx] = NULL; + } else { + /* + * dm->brightness[x] can be inconsistent just after startup until + * ops.get_brightness is called. + */ + real_brightness = + amdgpu_dm_backlight_ops.get_brightness(dm->backlight_dev[aconnector->bl_idx]); + + if (real_brightness != init_brightness) { + dm->actual_brightness[aconnector->bl_idx] = real_brightness; + dm->brightness[aconnector->bl_idx] = real_brightness; + } + drm_dbg_driver(drm, "DM: Registered Backlight device: %s\n", bl_name); + } +} + +void amdgpu_dm_update_connector_ext_caps(struct amdgpu_dm_connector *aconnector) +{ + const struct drm_panel_backlight_quirk *panel_backlight_quirk; + struct amdgpu_dm_backlight_caps *caps; + struct drm_connector *conn_base; + struct amdgpu_device *adev; + struct drm_luminance_range_info *luminance_range; + struct drm_device *drm; + + if (aconnector->bl_idx == -1 || + aconnector->dc_link->connector_signal != SIGNAL_TYPE_EDP) + return; + + conn_base = &aconnector->base; + drm = conn_base->dev; + adev = drm_to_adev(drm); + + caps = &adev->dm.backlight_caps[aconnector->bl_idx]; + caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps; + caps->aux_support = false; + + if (caps->ext_caps->bits.oled == 1 + /* + * || + * caps->ext_caps->bits.sdr_aux_backlight_control == 1 || + * caps->ext_caps->bits.hdr_aux_backlight_control == 1 + */) + caps->aux_support = true; + + if (amdgpu_backlight == 0) + caps->aux_support = false; + else if (amdgpu_backlight == 1) + caps->aux_support = true; + if (caps->aux_support) + aconnector->dc_link->backlight_control_type = BACKLIGHT_CONTROL_AMD_AUX; + + luminance_range = &conn_base->display_info.luminance_range; + + if (luminance_range->max_luminance) + caps->aux_max_input_signal = luminance_range->max_luminance; + else + caps->aux_max_input_signal = 512; + + if (luminance_range->min_luminance) + caps->aux_min_input_signal = luminance_range->min_luminance; + else + caps->aux_min_input_signal = 1; + + panel_backlight_quirk = + drm_get_panel_backlight_quirk(aconnector->drm_edid); + if (!IS_ERR_OR_NULL(panel_backlight_quirk)) { + if (panel_backlight_quirk->min_brightness) { + caps->min_input_signal = + panel_backlight_quirk->min_brightness - 1; + drm_info(drm, + "Applying panel backlight quirk, min_brightness: %d\n", + caps->min_input_signal); + } + if (panel_backlight_quirk->brightness_mask) { + drm_info(drm, + "Applying panel backlight quirk, brightness_mask: 0x%X\n", + panel_backlight_quirk->brightness_mask); + caps->brightness_mask = + panel_backlight_quirk->brightness_mask; + } + } +} +EXPORT_IF_KUNIT(amdgpu_dm_update_connector_ext_caps); + +void amdgpu_dm_setup_backlight_device(struct amdgpu_display_manager *dm, + struct amdgpu_dm_connector *aconnector) +{ + struct amdgpu_dm_backlight_caps *caps; + struct dc_link *link = aconnector->dc_link; + int bl_idx = dm->num_of_edps; + + if (!(link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) || + link->type == dc_connection_none) + return; + + if (dm->num_of_edps >= AMDGPU_DM_MAX_NUM_EDP) { + drm_warn(adev_to_drm(dm->adev), "Too much eDP connections, skipping backlight setup for additional eDPs\n"); + return; + } + + aconnector->bl_idx = bl_idx; + + amdgpu_dm_update_backlight_caps(dm, bl_idx); + dm->backlight_link[bl_idx] = link; + dm->num_of_edps++; + + amdgpu_dm_update_connector_ext_caps(aconnector); + caps = &dm->backlight_caps[aconnector->bl_idx]; + + /* Only offer ABM property when non-OLED and user didn't turn off by module parameter */ + if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0) + drm_object_attach_property(&aconnector->base.base, + dm->adev->mode_info.abm_level_property, + ABM_SYSFS_CONTROL); +} +EXPORT_IF_KUNIT(amdgpu_dm_setup_backlight_device); + +/** + * DOC: panel power savings + * + * The display manager allows you to set your desired **panel power savings** + * level (between 0-4, with 0 representing off), e.g. using the following:: + * + * # echo 3 > /sys/class/drm/card0-eDP-1/amdgpu/panel_power_savings + * + * Modifying this value can have implications on color accuracy, so tread + * carefully. + */ + +static ssize_t panel_power_savings_show(struct device *device, + struct device_attribute *attr, + char *buf) +{ + struct drm_connector *connector = dev_get_drvdata(device); + struct drm_device *dev = connector->dev; + u8 val; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + val = to_dm_connector_state(connector->state)->abm_level == + ABM_LEVEL_IMMEDIATE_DISABLE ? 0 : + to_dm_connector_state(connector->state)->abm_level; + drm_modeset_unlock(&dev->mode_config.connection_mutex); + + return sysfs_emit(buf, "%u\n", val); +} + +static ssize_t panel_power_savings_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct drm_connector *connector = dev_get_drvdata(device); + struct drm_device *dev = connector->dev; + long val; + int ret; + + ret = kstrtol(buf, 0, &val); + + if (ret) + return ret; + + if (val < 0 || val > 4) + return -EINVAL; + + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + if (to_dm_connector_state(connector->state)->abm_sysfs_forbidden) + ret = -EBUSY; + else + to_dm_connector_state(connector->state)->abm_level = val ?: + ABM_LEVEL_IMMEDIATE_DISABLE; + drm_modeset_unlock(&dev->mode_config.connection_mutex); + + if (ret) + return ret; + + drm_kms_helper_hotplug_event(dev); + + return count; +} + +static DEVICE_ATTR_RW(panel_power_savings); + +static struct attribute *amdgpu_attrs[] = { + &dev_attr_panel_power_savings.attr, + NULL +}; + +const struct attribute_group amdgpu_group = { + .name = "amdgpu", + .attrs = amdgpu_attrs +}; + +bool +amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *amdgpu_dm_connector) +{ + if (amdgpu_dm_abm_level >= 0) + return false; + + if (amdgpu_dm_connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) + return false; + + /* check for OLED panels */ + if (amdgpu_dm_connector->bl_idx >= 0) { + struct drm_device *drm = amdgpu_dm_connector->base.dev; + struct amdgpu_display_manager *dm = &drm_to_adev(drm)->dm; + struct amdgpu_dm_backlight_caps *caps; + + caps = &dm->backlight_caps[amdgpu_dm_connector->bl_idx]; + if (caps->aux_support) + return false; + } + + return true; +} +EXPORT_IF_KUNIT(amdgpu_dm_should_create_sysfs); + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +uint amdgpu_dm_get_dc_debug_mask(void) +{ + return amdgpu_dc_debug_mask; +} +EXPORT_IF_KUNIT(amdgpu_dm_get_dc_debug_mask); + +void amdgpu_dm_set_dc_debug_mask(uint val) +{ + amdgpu_dc_debug_mask = val; +} +EXPORT_IF_KUNIT(amdgpu_dm_set_dc_debug_mask); + +int amdgpu_dm_get_abm_level_param(void) +{ + return amdgpu_dm_abm_level; +} +EXPORT_IF_KUNIT(amdgpu_dm_get_abm_level_param); + +void amdgpu_dm_set_abm_level_param(int val) +{ + amdgpu_dm_abm_level = val; +} +EXPORT_IF_KUNIT(amdgpu_dm_set_abm_level_param); + +int amdgpu_dm_get_backlight_param(void) +{ + return amdgpu_backlight; +} +EXPORT_IF_KUNIT(amdgpu_dm_get_backlight_param); + +void amdgpu_dm_set_backlight_param(int val) +{ + amdgpu_backlight = val; +} +EXPORT_IF_KUNIT(amdgpu_dm_set_backlight_param); +#endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h new file mode 100644 index 000000000000..98d612c60ae9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __AMDGPU_DM_BACKLIGHT_H__ +#define __AMDGPU_DM_BACKLIGHT_H__ + +struct amdgpu_display_manager; +struct amdgpu_dm_connector; +struct backlight_device; +struct backlight_properties; +struct drm_connector; +struct attribute_group; + +#define AMDGPU_DM_DEFAULT_MIN_BACKLIGHT 12 +#define AMDGPU_DM_DEFAULT_MAX_BACKLIGHT 255 +#define AMDGPU_DM_MIN_SPREAD ((AMDGPU_DM_DEFAULT_MAX_BACKLIGHT - AMDGPU_DM_DEFAULT_MIN_BACKLIGHT) / 2) +#define AUX_BL_DEFAULT_TRANSITION_TIME_MS 50 + +void amdgpu_dm_update_backlight_caps(struct amdgpu_display_manager *dm, + int bl_idx); +void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm, + int bl_idx, u32 user_brightness); +void amdgpu_dm_register_backlight_device(struct amdgpu_dm_connector *aconnector); +void amdgpu_dm_setup_backlight_device(struct amdgpu_display_manager *dm, + struct amdgpu_dm_connector *aconnector); +void amdgpu_dm_update_connector_ext_caps(struct amdgpu_dm_connector *aconnector); +bool amdgpu_dm_should_create_sysfs(struct amdgpu_dm_connector *aconnector); + +extern const struct attribute_group amdgpu_group; + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps, + unsigned int *min, unsigned int *max); +void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps, + unsigned int min, unsigned int max, + uint32_t *user_brightness); +u32 convert_brightness_from_user(const struct amdgpu_dm_backlight_caps *caps, + uint32_t brightness); +u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *caps, + uint32_t brightness); +int amdgpu_dm_backlight_get_device_index(struct amdgpu_display_manager *dm, + struct backlight_device *bd); +void amdgpu_dm_backlight_fill_props(const struct amdgpu_dm_backlight_caps *caps, + bool is_system_supplied, + bool custom_curve_enabled, + struct backlight_properties *props); +uint amdgpu_dm_get_dc_debug_mask(void); +void amdgpu_dm_set_dc_debug_mask(uint val); +int amdgpu_dm_get_abm_level_param(void); +void amdgpu_dm_set_abm_level_param(int val); +int amdgpu_dm_get_backlight_param(void); +void amdgpu_dm_set_backlight_param(int val); +#endif + +#endif /* __AMDGPU_DM_BACKLIGHT_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c index 86086d10c543..357c7c5c85cf 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c @@ -1051,26 +1051,28 @@ EXPORT_IF_KUNIT(__drm_3dlut32_to_dc_3dlut); /* amdgpu_dm_atomic_lut3d - set DRM 3D LUT to DC stream * @drm_lut3d: user 3D LUT * @drm_lut3d_size: size of 3D LUT - * @lut3d: DC 3D LUT + * @cm: DC Color Manager (includes 3D LUT) * * Map user 3D LUT data to DC 3D LUT and all necessary bits to program it * on DCN accordingly. */ STATIC_IFN_KUNIT void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d, uint32_t drm_lut3d_size, - struct dc_3dlut *lut) + struct dc_plane_cm *cm) { if (!drm_lut3d_size) { - lut->state.bits.initialized = 0; + cm->lut3d_func.state.bits.initialized = 0; + cm->flags.bits.lut3d_enable = 0; } else { /* Stride and bit depth are not programmable by API yet. * Therefore, only supports 17x17x17 3D LUT (12-bit). */ - lut->lut_3d.use_tetrahedral_9 = false; - lut->lut_3d.use_12bits = true; - lut->state.bits.initialized = 1; - __drm_3dlut_to_dc_3dlut(drm_lut3d, drm_lut3d_size, &lut->lut_3d, - lut->lut_3d.use_tetrahedral_9, + cm->lut3d_func.lut_3d.use_tetrahedral_9 = false; + cm->lut3d_func.lut_3d.use_12bits = true; + cm->lut3d_func.state.bits.initialized = 1; + cm->flags.bits.lut3d_enable = 1; + __drm_3dlut_to_dc_3dlut(drm_lut3d, drm_lut3d_size, &cm->lut3d_func.lut_3d, + cm->lut3d_func.lut_3d.use_tetrahedral_9, MAX_COLOR_3DLUT_BITDEPTH); } } @@ -1080,7 +1082,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *sha bool has_rom, enum dc_transfer_func_predefined tf, uint32_t shaper_size, - struct dc_transfer_func *func_shaper) + struct dc_plane_cm *cm) { int ret = 0; @@ -1089,10 +1091,13 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *sha * If user shaper LUT is set, we assume a linear color space * (linearized by degamma 1D LUT or not). */ - __set_tf_distributed_points(func_shaper, tf); - ret = __set_output_tf(func_shaper, shaper_lut, shaper_size, has_rom); + __set_tf_distributed_points(&cm->shaper_func, tf); + cm->flags.bits.shaper_enable = 1; + + ret = __set_output_tf(&cm->shaper_func, shaper_lut, shaper_size, has_rom); } else { - __set_tf_bypass(func_shaper); + __set_tf_bypass(&cm->shaper_func); + cm->flags.bits.shaper_enable = 0; } return ret; @@ -1103,7 +1108,7 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blen bool has_rom, enum dc_transfer_func_predefined tf, uint32_t blend_size, - struct dc_transfer_func *func_blend) + struct dc_plane_cm *cm) { int ret = 0; @@ -1115,10 +1120,13 @@ STATIC_IFN_KUNIT int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blen * module to fill the parameters that will be translated to HW * points. */ - __set_tf_distributed_points(func_blend, tf); - ret = __set_input_tf(NULL, func_blend, blend_lut, blend_size); + __set_tf_distributed_points(&cm->blend_func, tf); + cm->flags.bits.blend_enable = 1; + + ret = __set_input_tf(NULL, &cm->blend_func, blend_lut, blend_size); } else { - __set_tf_bypass(func_blend); + __set_tf_bypass(&cm->blend_func); + cm->flags.bits.blend_enable = 0; } return ret; @@ -1461,7 +1469,7 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, const struct drm_color_lut *degamma_lut; enum amdgpu_transfer_function tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; uint32_t degamma_size; - bool has_degamma_lut; + bool has_degamma_lut, is_subsampled_format; int ret; degamma_lut = __extract_blob_lut(dm_plane_state->degamma_lut, @@ -1491,12 +1499,20 @@ __set_dm_plane_degamma(struct drm_plane_state *plane_state, if (ret) return ret; } else { - dc_plane_state->in_transfer_func.type = - TF_TYPE_PREDEFINED; + /* Check if format requires post-scale color processing (subsampled formats) */ + is_subsampled_format = (dc_plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN && + dc_plane_state->format < SURFACE_PIXEL_FORMAT_SUBSAMPLE_END); + + dc_plane_state->in_transfer_func.type = TF_TYPE_PREDEFINED; if (!mod_color_calculate_degamma_params(color_caps, - &dc_plane_state->in_transfer_func, NULL, false)) + &dc_plane_state->in_transfer_func, + NULL, + is_subsampled_format)) { + drm_err(plane_state->state->dev, + "Failed to calculate degamma params.\n"); return -ENOMEM; + } } return 0; } @@ -1632,30 +1648,47 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state, struct drm_colorop *colorop) { struct drm_colorop *old_colorop; - struct drm_colorop_state *colorop_state = NULL, *new_colorop_state; + struct drm_colorop_state *new_colorop_state; + struct drm_colorop_state *tf_state = NULL, *lut_state = NULL; struct drm_atomic_commit *state = plane_state->state; + struct drm_colorop *lut_colorop; enum dc_transfer_func_predefined default_tf = TRANSFER_FUNCTION_LINEAR; - struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func; + struct dc_transfer_func *tf = &dc_plane_state->cm.shaper_func; const struct drm_color_lut32 *shaper_lut; struct drm_device *dev = colorop->dev; bool enabled = false; u32 shaper_size; int i = 0, ret = 0; - /* 1D Curve - SHAPER TF */ + /* 1D Curve - SHAPER TF: find state */ old_colorop = colorop; for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { if (new_colorop_state->colorop == old_colorop && (BIT(new_colorop_state->curve_1d_type) & amdgpu_dm_supported_shaper_tfs)) { - colorop_state = new_colorop_state; + tf_state = new_colorop_state; break; } } - if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_CURVE) { - drm_dbg(dev, "Shaper TF colorop with ID: %d\n", colorop->base.id); + /* 1D LUT - SHAPER LUT: find state */ + lut_colorop = old_colorop->next; + if (!lut_colorop) { + drm_dbg(dev, "no Shaper LUT colorop found\n"); + return -EINVAL; + } + + for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { + if (new_colorop_state->colorop == lut_colorop && + new_colorop_state->colorop->type == DRM_COLOROP_1D_LUT) { + lut_state = new_colorop_state; + break; + } + } + + if (tf_state && !tf_state->bypass) { + drm_dbg(dev, "Shaper TF colorop with ID: %d\n", old_colorop->base.id); tf->type = TF_TYPE_DISTRIBUTED_POINTS; - tf->tf = default_tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type); + tf->tf = default_tf = amdgpu_colorop_tf_to_dc_tf(tf_state->curve_1d_type); tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; ret = __set_output_tf(tf, 0, 0, false); if (ret) @@ -1663,32 +1696,16 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state, enabled = true; } - /* 1D LUT - SHAPER LUT */ - colorop = old_colorop->next; - if (!colorop) { - drm_dbg(dev, "no Shaper LUT colorop found\n"); - return -EINVAL; - } - - old_colorop = colorop; - for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { - if (new_colorop_state->colorop == old_colorop && - new_colorop_state->colorop->type == DRM_COLOROP_1D_LUT) { - colorop_state = new_colorop_state; - break; - } - } - - if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_LUT) { - drm_dbg(dev, "Shaper LUT colorop with ID: %d\n", colorop->base.id); + if (lut_state && !lut_state->bypass) { + drm_dbg(dev, "Shaper LUT colorop with ID: %d\n", lut_colorop->base.id); tf->type = TF_TYPE_DISTRIBUTED_POINTS; tf->tf = default_tf; tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; - shaper_lut = __extract_blob_lut32(colorop_state->data, &shaper_size); + shaper_lut = __extract_blob_lut32(lut_state->data, &shaper_size); shaper_size = shaper_lut != NULL ? shaper_size : 0; /* Custom LUT size must be the same as supported size */ - if (shaper_size == colorop->size) { + if (shaper_size == lut_colorop->size) { ret = __set_output_tf_32(tf, shaper_lut, shaper_size, false); if (ret) return ret; @@ -1696,8 +1713,12 @@ __set_dm_plane_colorop_shaper(struct drm_plane_state *plane_state, } } - if (!enabled) + if (!enabled) { tf->type = TF_TYPE_BYPASS; + dc_plane_state->cm.flags.bits.shaper_enable = 0; + } else { + dc_plane_state->cm.flags.bits.shaper_enable = 1; + } return 0; } @@ -1741,7 +1762,7 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state, { struct drm_colorop *old_colorop; struct drm_colorop_state *colorop_state = NULL, *new_colorop_state; - struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func; + struct dc_transfer_func *tf = &dc_plane_state->cm.shaper_func; struct drm_atomic_commit *state = plane_state->state; const struct amdgpu_device *adev = drm_to_adev(colorop->dev); bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend; @@ -1769,13 +1790,15 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state, drm_dbg(dev, "3D LUT colorop with ID: %d\n", colorop->base.id); lut3d = __extract_blob_lut32(colorop_state->data, &lut3d_size); lut3d_size = lut3d != NULL ? lut3d_size : 0; - ret = __set_colorop_3dlut(lut3d, lut3d_size, &dc_plane_state->lut3d_func); + ret = __set_colorop_3dlut(lut3d, lut3d_size, &dc_plane_state->cm.lut3d_func); if (ret) { drm_dbg(dev, "3D LUT colorop with ID: %d has LUT size = %d\n", colorop->base.id, lut3d_size); return ret; } + dc_plane_state->cm.flags.bits.lut3d_enable = 1; + /* 3D LUT requires shaper. If shaper colorop is bypassed, enable shaper curve * with TRANSFER_FUNCTION_LINEAR */ @@ -1785,6 +1808,8 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state, tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; ret = __set_output_tf_32(tf, NULL, 0, false); } + } else { + dc_plane_state->cm.flags.bits.lut3d_enable = 0; } return ret; @@ -1796,61 +1821,64 @@ __set_dm_plane_colorop_blend(struct drm_plane_state *plane_state, struct drm_colorop *colorop) { struct drm_colorop *old_colorop; - struct drm_colorop_state *colorop_state = NULL, *new_colorop_state; + struct drm_colorop_state *new_colorop_state; + struct drm_colorop_state *tf_state = NULL, *lut_state = NULL; struct drm_atomic_commit *state = plane_state->state; + struct drm_colorop *lut_colorop; enum dc_transfer_func_predefined default_tf = TRANSFER_FUNCTION_LINEAR; - struct dc_transfer_func *tf = &dc_plane_state->blend_tf; + struct dc_transfer_func *tf = &dc_plane_state->cm.blend_func; const struct drm_color_lut32 *blend_lut = NULL; struct drm_device *dev = colorop->dev; uint32_t blend_size = 0; int i = 0; - /* 1D Curve - BLND TF */ + dc_plane_state->cm.flags.bits.blend_enable = 0; + + /* 1D Curve - BLND TF: find state */ old_colorop = colorop; for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { if (new_colorop_state->colorop == old_colorop && (BIT(new_colorop_state->curve_1d_type) & amdgpu_dm_supported_blnd_tfs)) { - colorop_state = new_colorop_state; + tf_state = new_colorop_state; break; } } - if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_CURVE && - (BIT(colorop_state->curve_1d_type) & amdgpu_dm_supported_blnd_tfs)) { - drm_dbg(dev, "Blend TF colorop with ID: %d\n", colorop->base.id); - tf->type = TF_TYPE_DISTRIBUTED_POINTS; - tf->tf = default_tf = amdgpu_colorop_tf_to_dc_tf(colorop_state->curve_1d_type); - tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; - __set_input_tf_32(NULL, tf, blend_lut, blend_size); - } - - /* 1D Curve - BLND LUT */ - colorop = old_colorop->next; - if (!colorop) { + /* 1D LUT - BLND LUT: find state */ + lut_colorop = old_colorop->next; + if (!lut_colorop) { drm_dbg(dev, "no Blend LUT colorop found\n"); return -EINVAL; } - old_colorop = colorop; for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { - if (new_colorop_state->colorop == old_colorop && + if (new_colorop_state->colorop == lut_colorop && new_colorop_state->colorop->type == DRM_COLOROP_1D_LUT) { - colorop_state = new_colorop_state; + lut_state = new_colorop_state; break; } } - if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_1D_LUT && - (BIT(colorop_state->curve_1d_type) & amdgpu_dm_supported_blnd_tfs)) { - drm_dbg(dev, "Blend LUT colorop with ID: %d\n", colorop->base.id); + if (tf_state && !tf_state->bypass) { + drm_dbg(dev, "Blend TF colorop with ID: %d\n", old_colorop->base.id); + tf->type = TF_TYPE_DISTRIBUTED_POINTS; + tf->tf = default_tf = amdgpu_colorop_tf_to_dc_tf(tf_state->curve_1d_type); + tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; + dc_plane_state->cm.flags.bits.blend_enable = 1; + __set_input_tf_32(NULL, tf, blend_lut, blend_size); + } + + if (lut_state && !lut_state->bypass) { + drm_dbg(dev, "Blend LUT colorop with ID: %d\n", lut_colorop->base.id); tf->type = TF_TYPE_DISTRIBUTED_POINTS; tf->tf = default_tf; tf->sdr_ref_white_level = SDR_WHITE_LEVEL_INIT_VALUE; - blend_lut = __extract_blob_lut32(colorop_state->data, &blend_size); + dc_plane_state->cm.flags.bits.blend_enable = 1; + blend_lut = __extract_blob_lut32(lut_state->data, &blend_size); blend_size = blend_lut != NULL ? blend_size : 0; /* Custom LUT size must be the same as supported size */ - if (blend_size == colorop->size) + if (blend_size == lut_colorop->size) __set_input_tf_32(NULL, tf, blend_lut, blend_size); } @@ -1876,11 +1904,11 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, lut3d = __extract_blob_lut(dm_plane_state->lut3d, &lut3d_size); lut3d_size = lut3d != NULL ? lut3d_size : 0; - amdgpu_dm_atomic_lut3d(lut3d, lut3d_size, &dc_plane_state->lut3d_func); + amdgpu_dm_atomic_lut3d(lut3d, lut3d_size, &dc_plane_state->cm); ret = amdgpu_dm_atomic_shaper_lut(shaper_lut, false, amdgpu_tf_to_dc_tf(shaper_tf), shaper_size, - &dc_plane_state->in_shaper_func); + &dc_plane_state->cm); if (ret) { drm_dbg_kms(plane_state->plane->dev, "setting plane %d shaper LUT failed.\n", @@ -1895,7 +1923,8 @@ amdgpu_dm_plane_set_color_properties(struct drm_plane_state *plane_state, ret = amdgpu_dm_atomic_blend_lut(blend_lut, false, amdgpu_tf_to_dc_tf(blend_tf), - blend_size, &dc_plane_state->blend_tf); + blend_size, &dc_plane_state->cm); + if (ret) { drm_dbg_kms(plane_state->plane->dev, "setting plane %d gamma lut failed.\n", diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h index e4f53b7bc753..8dbbcb3ab156 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.h @@ -87,10 +87,10 @@ void __drm_3dlut32_to_dc_3dlut(const struct drm_color_lut32 *lut, struct tetrahedral_params *params, bool use_tetrahedral_9, int bit_depth); -struct dc_3dlut; +struct dc_plane_cm; void amdgpu_dm_atomic_lut3d(const struct drm_color_lut *drm_lut3d, uint32_t drm_lut3d_size, - struct dc_3dlut *lut); + struct dc_plane_cm *cm); int __set_colorop_3dlut(const struct drm_color_lut32 *drm_lut3d, uint32_t drm_lut3d_size, struct dc_3dlut *lut); @@ -105,12 +105,12 @@ int amdgpu_dm_atomic_shaper_lut(const struct drm_color_lut *shaper_lut, bool has_rom, enum dc_transfer_func_predefined tf, uint32_t shaper_size, - struct dc_transfer_func *func_shaper); + struct dc_plane_cm *cm); int amdgpu_dm_atomic_blend_lut(const struct drm_color_lut *blend_lut, bool has_rom, enum dc_transfer_func_predefined tf, uint32_t blend_size, - struct dc_transfer_func *func_blend); + struct dc_plane_cm *cm); int __set_colorop_in_tf_1d_curve(struct dc_plane_state *dc_plane_state, struct drm_colorop_state *colorop_state); #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c index 48f5c431eaf9..056a76b88f43 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c @@ -235,3 +235,4 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr return amdgpu_dm_build_default_pipeline(dev, plane, hw_3d_lut, list); } +EXPORT_IF_KUNIT(amdgpu_dm_initialize_default_pipeline); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c new file mode 100644 index 000000000000..88f938a8f24f --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c @@ -0,0 +1,3663 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services_types.h" +#include "dc.h" +#include "dc/dc_dmub_srv.h" +#include "dc/dc_edid_parser.h" +#include "dc/dc_stat.h" +#include "dc/dc_state.h" +#include "dc/dc_stream.h" +#include "dc/inc/core_types.h" +#include "link_enc_cfg.h" +#include "link/protocols/link_dpcd.h" +#include "link_service_types.h" +#include "link/protocols/link_dp_capability.h" +#include "link/protocols/link_ddc.h" + +#include "amdgpu.h" +#include "amdgpu_display.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_connector.h" +#include "amdgpu_dm_kunit_helpers.h" +#include "amdgpu_dm_plane.h" +#include "amdgpu_dm_crtc.h" +#include "amdgpu_dm_wb.h" +#include "amdgpu_dm_mst_types.h" +#if defined(CONFIG_DEBUG_FS) +#include "amdgpu_dm_debugfs.h" +#endif +#include "amdgpu_dm_backlight.h" +#include "amdgpu_dm_audio.h" +#include "amdgpu_dm_irq.h" +#include "amdgpu_dm_psr.h" +#include "dm_helpers.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "modules/inc/mod_freesync.h" +#include "modules/inc/mod_power.h" + +#include "amdgpu_dm_trace.h" + +/* Encoder functions */ + +static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder) +{ + drm_encoder_cleanup(encoder); + kfree(encoder); +} + +static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = { + .destroy = amdgpu_dm_encoder_destroy, +}; + +static void dm_encoder_helper_disable(struct drm_encoder *encoder) +{ +} + +static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct drm_atomic_commit *state = crtc_state->state; + struct drm_connector *connector = conn_state->connector; + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct dm_connector_state *dm_new_connector_state = to_dm_connector_state(conn_state); + const struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + struct drm_dp_mst_topology_mgr *mst_mgr; + struct drm_dp_mst_port *mst_port; + struct drm_dp_mst_topology_state *mst_state; + enum dc_color_depth color_depth; + int clock, bpp = 0; + bool is_y420 = false; + + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) || + (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)) { + struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); + struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; + enum drm_mode_status result; + + result = drm_crtc_helper_mode_valid_fixed(encoder->crtc, adjusted_mode, native_mode); + if (result != MODE_OK && dm_new_connector_state->scaling == RMX_OFF) { + drm_dbg_driver(encoder->dev, + "mode %dx%d@%dHz is not native, enabling scaling\n", + adjusted_mode->hdisplay, adjusted_mode->vdisplay, + drm_mode_vrefresh(adjusted_mode)); + dm_new_connector_state->scaling = RMX_ASPECT; + } + return 0; + } + + if (!aconnector->mst_output_port) + return 0; + + mst_port = aconnector->mst_output_port; + mst_mgr = &aconnector->mst_root->mst_mgr; + + if (!crtc_state->connectors_changed && !crtc_state->mode_changed) + return 0; + + mst_state = drm_atomic_get_mst_topology_state(state, mst_mgr); + if (IS_ERR(mst_state)) + return PTR_ERR(mst_state); + + mst_state->pbn_div.full = dm_mst_get_pbn_divider(aconnector->mst_root->dc_link); + + if (!state->duplicated) { + int max_bpc = conn_state->max_requested_bpc; + + is_y420 = drm_mode_is_420_also(&connector->display_info, adjusted_mode) && + aconnector->force_yuv420_output; + color_depth = amdgpu_dm_convert_color_depth_from_display_info(connector, + is_y420, + max_bpc); + bpp = amdgpu_dm_convert_dc_color_depth_into_bpc(color_depth) * 3; + clock = adjusted_mode->clock; + dm_new_connector_state->pbn = drm_dp_calc_pbn_mode(clock, bpp << 4); + } + + dm_new_connector_state->vcpi_slots = + drm_dp_atomic_find_time_slots(state, mst_mgr, mst_port, + dm_new_connector_state->pbn); + if (dm_new_connector_state->vcpi_slots < 0) { + drm_dbg_atomic(connector->dev, "failed finding vcpi slots: %d\n", (int)dm_new_connector_state->vcpi_slots); + return dm_new_connector_state->vcpi_slots; + } + return 0; +} + +const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = { + .disable = dm_encoder_helper_disable, + .atomic_check = dm_encoder_helper_atomic_check +}; + +int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev) +{ + switch (adev->mode_info.num_crtc) { + case 1: + return 0x1; + case 2: + return 0x3; + case 3: + return 0x7; + case 4: + return 0xf; + case 5: + return 0x1f; + case 6: + default: + return 0x3f; + } +} +EXPORT_IF_KUNIT(amdgpu_dm_get_encoder_crtc_mask); + +int amdgpu_dm_encoder_init(struct drm_device *dev, + struct amdgpu_encoder *aencoder, + uint32_t link_index) +{ + struct amdgpu_device *adev = drm_to_adev(dev); + + int res = drm_encoder_init(dev, + &aencoder->base, + &amdgpu_dm_encoder_funcs, + DRM_MODE_ENCODER_TMDS, + NULL); + + aencoder->base.possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev); + + if (!res) + aencoder->encoder_id = link_index; + else + aencoder->encoder_id = -1; + + drm_encoder_helper_add(&aencoder->base, &amdgpu_dm_encoder_helper_funcs); + + return res; +} + +STATIC_IFN_KUNIT enum drm_mode_subconnector get_subconnector_type(struct dc_link *link) +{ + switch (link->dpcd_caps.dongle_type) { + case DISPLAY_DONGLE_NONE: + return DRM_MODE_SUBCONNECTOR_Native; + case DISPLAY_DONGLE_DP_VGA_CONVERTER: + return DRM_MODE_SUBCONNECTOR_VGA; + case DISPLAY_DONGLE_DP_DVI_CONVERTER: + case DISPLAY_DONGLE_DP_DVI_DONGLE: + return DRM_MODE_SUBCONNECTOR_DVID; + case DISPLAY_DONGLE_DP_HDMI_CONVERTER: + case DISPLAY_DONGLE_DP_HDMI_DONGLE: + return DRM_MODE_SUBCONNECTOR_HDMIA; + case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE: + default: + return DRM_MODE_SUBCONNECTOR_Unknown; + } +} +EXPORT_IF_KUNIT(get_subconnector_type); + +static void update_subconnector_property(struct amdgpu_dm_connector *aconnector) +{ + struct dc_link *link = aconnector->dc_link; + struct drm_connector *connector = &aconnector->base; + enum drm_mode_subconnector subconnector = DRM_MODE_SUBCONNECTOR_Unknown; + + if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) + return; + + if (aconnector->dc_sink) + subconnector = get_subconnector_type(link); + + drm_object_property_set_value(&connector->base, + connector->dev->mode_config.dp_subconnector_property, + subconnector); +} + +static int amdgpu_dm_connector_get_modes(struct drm_connector *connector); + +static void amdgpu_dm_fbc_init(struct drm_connector *connector) +{ + struct amdgpu_device *adev = drm_to_adev(connector->dev); + struct dm_compressor_info *compressor = &adev->dm.compressor; + struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(connector); + struct drm_display_mode *mode; + unsigned long max_size = 0; + + if (adev->dm.dc->fbc_compressor == NULL) + return; + + if (aconn->dc_link->connector_signal != SIGNAL_TYPE_EDP) + return; + + if (compressor->bo_ptr) + return; + + + list_for_each_entry(mode, &connector->modes, head) { + if (max_size < (unsigned long) mode->htotal * mode->vtotal) + max_size = (unsigned long) mode->htotal * mode->vtotal; + } + + if (max_size) { + int r = amdgpu_bo_create_kernel(adev, max_size * 4, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_GTT, &compressor->bo_ptr, + &compressor->gpu_addr, &compressor->cpu_addr); + + if (r) + drm_err(adev_to_drm(adev), "DM: Failed to initialize FBC\n"); + else { + adev->dm.dc->ctx->fbc_gpu_addr = compressor->gpu_addr; + drm_info(adev_to_drm(adev), "DM: FBC alloc %lu\n", max_size*4); + } + + } + +} + + +int amdgpu_dm_detect_mst_link_for_all_connectors(struct drm_device *dev) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_connector *connector; + struct drm_connector_list_iter iter; + int ret = 0; + + drm_connector_list_iter_begin(dev, &iter); + drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->dc_link->type == dc_connection_mst_branch && + aconnector->mst_mgr.aux) { + drm_dbg_kms(dev, "DM_MST: starting TM on aconnector: %p [id: %d]\n", + aconnector, + aconnector->base.base.id); + + ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true); + if (ret < 0) { + drm_err(dev, "DM_MST: Failed to start MST\n"); + aconnector->dc_link->type = + dc_connection_single; + ret = dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx, + aconnector->dc_link); + break; + } + } + } + drm_connector_list_iter_end(&iter); + + return ret; +} + +static void hdmi_cec_unset_edid(struct amdgpu_dm_connector *aconnector) +{ + struct cec_notifier *n = aconnector->notifier; + + if (!n) + return; + + cec_notifier_phys_addr_invalidate(n); +} + +void amdgpu_dm_hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector) +{ + struct drm_connector *connector = &aconnector->base; + struct cec_notifier *n = aconnector->notifier; + + if (!n) + return; + + cec_notifier_set_phys_addr(n, + connector->display_info.source_physical_address); +} + +void amdgpu_dm_s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + + drm_connector_list_iter_begin(ddev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + if (suspend) + hdmi_cec_unset_edid(aconnector); + else + amdgpu_dm_hdmi_cec_set_edid(aconnector); + } + drm_connector_list_iter_end(&conn_iter); +} + + +struct drm_connector * +amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_commit *state, + struct drm_crtc *crtc) +{ + u32 i; + struct drm_connector_state *new_con_state; + struct drm_connector *connector; + struct drm_crtc *crtc_from_state; + + for_each_new_connector_in_state(state, connector, new_con_state, i) { + crtc_from_state = new_con_state->crtc; + + if (crtc_from_state == crtc) + return connector; + } + + return NULL; +} + +static void dm_set_panel_type(struct amdgpu_dm_connector *aconnector) +{ + struct drm_connector *connector = &aconnector->base; + struct drm_display_info *display_info = &connector->display_info; + struct dc_link *link = aconnector->dc_link; + struct amdgpu_device *adev; + + adev = drm_to_adev(connector->dev); + + link->panel_type = PANEL_TYPE_NONE; + + switch (display_info->amd_vsdb.panel_type) { + case AMD_VSDB_PANEL_TYPE_OLED: + link->panel_type = PANEL_TYPE_OLED; + break; + case AMD_VSDB_PANEL_TYPE_MINILED: + link->panel_type = PANEL_TYPE_MINILED; + break; + } + + /* If VSDB didn't determine panel type, check DPCD ext caps */ + if (link->panel_type == PANEL_TYPE_NONE) { + if (link->dpcd_sink_ext_caps.bits.miniled == 1) + link->panel_type = PANEL_TYPE_MINILED; + if (link->dpcd_sink_ext_caps.bits.oled == 1) + link->panel_type = PANEL_TYPE_OLED; + } + + /* If VSDB and DPCD didn't determine panel type, check DID */ + if (link->panel_type == PANEL_TYPE_NONE) { + if (display_info->panel_type == DRM_MODE_PANEL_TYPE_LCD) + link->panel_type = PANEL_TYPE_LCD; + else if (display_info->panel_type == DRM_MODE_PANEL_TYPE_OLED) + link->panel_type = PANEL_TYPE_OLED; + } + + if (link->panel_type == PANEL_TYPE_NONE) { + struct drm_amd_vsdb_info *vsdb = &display_info->amd_vsdb; + u32 lum1_max = vsdb->luminance_range1.max_luminance; + u32 lum2_max = vsdb->luminance_range2.max_luminance; + + if (vsdb->version && link->local_sink && + link->local_sink->edid_caps.manufacturer_id == + DDC_MANUFACTURERNAME_SAMSUNG && + lum1_max >= ((lum2_max * 3) / 2)) + link->panel_type = PANEL_TYPE_MINILED; + } + + if (link->panel_type == PANEL_TYPE_OLED) + drm_object_property_set_value(&connector->base, + adev_to_drm(adev)->mode_config.panel_type_property, + DRM_MODE_PANEL_TYPE_OLED); + else if (link->panel_type == PANEL_TYPE_LCD) + drm_object_property_set_value(&connector->base, + adev_to_drm(adev)->mode_config.panel_type_property, + DRM_MODE_PANEL_TYPE_LCD); + else + drm_object_property_set_value(&connector->base, + adev_to_drm(adev)->mode_config.panel_type_property, + DRM_MODE_PANEL_TYPE_UNKNOWN); + + drm_dbg_kms(aconnector->base.dev, "Panel type: %d\n", link->panel_type); +} + +DEFINE_FREE(sink_release, struct dc_sink *, if (_T) dc_sink_release(_T)) + +void amdgpu_dm_update_connector_after_detect( + struct amdgpu_dm_connector *aconnector) +{ + struct drm_connector *connector = &aconnector->base; + struct dc_sink *sink __free(sink_release) = NULL; + struct drm_device *dev = connector->dev; + + /* MST handled by drm_mst framework */ + if (aconnector->mst_mgr.mst_state) + return; + + sink = aconnector->dc_link->local_sink; + if (sink) + dc_sink_retain(sink); + + /* + * Edid mgmt connector gets first update only in mode_valid hook and then + * the connector sink is set to either fake or physical sink depends on link status. + * Skip if already done during boot. + */ + if (aconnector->base.force != DRM_FORCE_UNSPECIFIED + && aconnector->dc_em_sink) { + + /* + * For S3 resume with headless use eml_sink to fake stream + * because on resume connector->sink is set to NULL + */ + guard(mutex)(&dev->mode_config.mutex); + + if (sink) { + if (aconnector->dc_sink) { + amdgpu_dm_update_freesync_caps(connector, NULL, true); + /* + * retain and release below are used to + * bump up refcount for sink because the link doesn't point + * to it anymore after disconnect, so on next crtc to connector + * reshuffle by UMD we will get into unwanted dc_sink release + */ + dc_sink_release(aconnector->dc_sink); + } + aconnector->dc_sink = sink; + dc_sink_retain(aconnector->dc_sink); + amdgpu_dm_update_freesync_caps(connector, + aconnector->drm_edid, true); + } else { + amdgpu_dm_update_freesync_caps(connector, NULL, true); + if (!aconnector->dc_sink) { + aconnector->dc_sink = aconnector->dc_em_sink; + dc_sink_retain(aconnector->dc_sink); + } + } + + return; + } + + /* + * TODO: temporary guard to look for proper fix + * if this sink is MST sink, we should not do anything + */ + if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) + return; + + if (aconnector->dc_sink == sink) { + /* + * We got a DP short pulse (Link Loss, DP CTS, etc...). + * Do nothing!! + */ + drm_dbg_kms(dev, "DCHPD: connector_id=%d: dc_sink didn't change.\n", + aconnector->connector_id); + return; + } + + drm_dbg_kms(dev, "DCHPD: connector_id=%d: Old sink=%p New sink=%p\n", + aconnector->connector_id, aconnector->dc_sink, sink); + + /* When polling, DRM has already locked the mutex for us. */ + if (!drm_kms_helper_is_poll_worker()) + mutex_lock(&dev->mode_config.mutex); + + /* + * 1. Update status of the drm connector + * 2. Send an event and let userspace tell us what to do + */ + if (sink) { + /* + * TODO: check if we still need the S3 mode update workaround. + * If yes, put it here. + */ + if (aconnector->dc_sink) { + amdgpu_dm_update_freesync_caps(connector, NULL, true); + dc_sink_release(aconnector->dc_sink); + } + + aconnector->dc_sink = sink; + dc_sink_retain(aconnector->dc_sink); + drm_edid_free(aconnector->drm_edid); + aconnector->drm_edid = NULL; + if (sink->dc_edid.length == 0) { + hdmi_cec_unset_edid(aconnector); + if (aconnector->dc_link->aux_mode) + drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); + } else { + const struct edid *edid = (const struct edid *)sink->dc_edid.raw_edid; + + aconnector->drm_edid = drm_edid_alloc(edid, sink->dc_edid.length); + drm_edid_connector_update(connector, aconnector->drm_edid); + + amdgpu_dm_hdmi_cec_set_edid(aconnector); + if (aconnector->dc_link->aux_mode) + drm_dp_cec_attach(&aconnector->dm_dp_aux.aux, + connector->display_info.source_physical_address); + } + + if (!aconnector->timing_requested) { + aconnector->timing_requested = + kzalloc_obj(struct dc_crtc_timing); + if (!aconnector->timing_requested) + drm_err(dev, + "failed to create aconnector->requested_timing\n"); + } + + amdgpu_dm_update_freesync_caps(connector, aconnector->drm_edid, true); + amdgpu_dm_update_connector_ext_caps(aconnector); + dm_set_panel_type(aconnector); + + if (aconnector->hdmi_comp_auto) { + if (sink->sink_signal != SIGNAL_TYPE_HDMI_FRL) + sink->sink_signal = SIGNAL_TYPE_HDMI_FRL; + } + } else { + hdmi_cec_unset_edid(aconnector); + drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); + amdgpu_dm_update_freesync_caps(connector, NULL, true); + aconnector->num_modes = 0; + dc_sink_release(aconnector->dc_sink); + aconnector->dc_sink = NULL; + drm_edid_free(aconnector->drm_edid); + aconnector->drm_edid = NULL; + kfree(aconnector->timing_requested); + aconnector->timing_requested = NULL; + /* Set CP to DESIRED if it was ENABLED, so we can re-enable it again on hotplug */ + if (connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) + connector->state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + } + + update_subconnector_property(aconnector); + + /* When polling, the mutex will be unlocked for us by DRM. */ + if (!drm_kms_helper_is_poll_worker()) + mutex_unlock(&dev->mode_config.mutex); +} + +enum dc_color_depth +amdgpu_dm_convert_color_depth_from_display_info(const struct drm_connector *connector, + bool is_y420, int requested_bpc) +{ + u8 bpc; + + if (is_y420) { + bpc = 8; + + /* Cap display bpc based on HDMI 2.0 HF-VSDB */ + if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_48) + bpc = 16; + else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_36) + bpc = 12; + else if (connector->display_info.hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30) + bpc = 10; + } else { + bpc = (uint8_t)connector->display_info.bpc; + /* Assume 8 bpc by default if no bpc is specified. */ + bpc = bpc ? bpc : 8; + } + + if (requested_bpc > 0) { + /* + * Cap display bpc based on the user requested value. + * + * The value for state->max_bpc may not correctly updated + * depending on when the connector gets added to the state + * or if this was called outside of atomic check, so it + * can't be used directly. + */ + bpc = min_t(u8, bpc, requested_bpc); + + /* Round down to the nearest even number. */ + bpc = bpc - (bpc & 1); + } + + switch (bpc) { + case 0: + /* + * Temporary Work around, DRM doesn't parse color depth for + * EDID revision before 1.4 + * TODO: Fix edid parsing + */ + return COLOR_DEPTH_888; + case 6: + return COLOR_DEPTH_666; + case 8: + return COLOR_DEPTH_888; + case 10: + return COLOR_DEPTH_101010; + case 12: + return COLOR_DEPTH_121212; + case 14: + return COLOR_DEPTH_141414; + case 16: + return COLOR_DEPTH_161616; + default: + return COLOR_DEPTH_UNDEFINED; + } +} +EXPORT_IF_KUNIT(amdgpu_dm_convert_color_depth_from_display_info); + +STATIC_IFN_KUNIT enum dc_aspect_ratio +get_aspect_ratio(const struct drm_display_mode *mode_in) +{ + /* 1-1 mapping, since both enums follow the HDMI spec. */ + return (enum dc_aspect_ratio) mode_in->picture_aspect_ratio; +} +EXPORT_IF_KUNIT(get_aspect_ratio); + +enum dc_color_space +amdgpu_dm_get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, + const struct drm_connector_state *connector_state) +{ + enum dc_color_space color_space = COLOR_SPACE_SRGB; + + switch (connector_state->colorspace) { + case DRM_MODE_COLORIMETRY_BT601_YCC: + if (dc_crtc_timing->flags.Y_ONLY) + color_space = COLOR_SPACE_YCBCR601_LIMITED; + else + color_space = COLOR_SPACE_YCBCR601; + break; + case DRM_MODE_COLORIMETRY_BT709_YCC: + if (dc_crtc_timing->flags.Y_ONLY) + color_space = COLOR_SPACE_YCBCR709_LIMITED; + else + color_space = COLOR_SPACE_YCBCR709; + break; + case DRM_MODE_COLORIMETRY_OPRGB: + color_space = COLOR_SPACE_ADOBERGB; + break; + case DRM_MODE_COLORIMETRY_BT2020_RGB: + case DRM_MODE_COLORIMETRY_BT2020_YCC: + if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) + color_space = COLOR_SPACE_2020_RGB_FULLRANGE; + else + color_space = COLOR_SPACE_2020_YCBCR_LIMITED; + break; + case DRM_MODE_COLORIMETRY_DEFAULT: /* ITU601 */ + default: + if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) { + color_space = COLOR_SPACE_SRGB; + if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED) + color_space = COLOR_SPACE_SRGB_LIMITED; + /* + * 27030khz is the separation point between HDTV and SDTV + * according to HDMI spec, we use YCbCr709 and YCbCr601 + * respectively + */ + } else if (dc_crtc_timing->pix_clk_100hz > 270300) { + if (dc_crtc_timing->flags.Y_ONLY) + color_space = + COLOR_SPACE_YCBCR709_LIMITED; + else + color_space = COLOR_SPACE_YCBCR709; + } else { + if (dc_crtc_timing->flags.Y_ONLY) + color_space = + COLOR_SPACE_YCBCR601_LIMITED; + else + color_space = COLOR_SPACE_YCBCR601; + } + break; + } + + return color_space; +} +EXPORT_IF_KUNIT(amdgpu_dm_get_output_color_space); + +STATIC_IFN_KUNIT enum display_content_type +get_output_content_type(const struct drm_connector_state *connector_state) +{ + switch (connector_state->content_type) { + default: + case DRM_MODE_CONTENT_TYPE_NO_DATA: + return DISPLAY_CONTENT_TYPE_NO_DATA; + case DRM_MODE_CONTENT_TYPE_GRAPHICS: + return DISPLAY_CONTENT_TYPE_GRAPHICS; + case DRM_MODE_CONTENT_TYPE_PHOTO: + return DISPLAY_CONTENT_TYPE_PHOTO; + case DRM_MODE_CONTENT_TYPE_CINEMA: + return DISPLAY_CONTENT_TYPE_CINEMA; + case DRM_MODE_CONTENT_TYPE_GAME: + return DISPLAY_CONTENT_TYPE_GAME; + } +} +EXPORT_IF_KUNIT(get_output_content_type); + +STATIC_IFN_KUNIT bool adjust_colour_depth_from_display_info( + struct dc_crtc_timing *timing_out, + const struct drm_display_info *info) +{ + enum dc_color_depth depth = timing_out->display_color_depth; + int normalized_clk; + + do { + normalized_clk = timing_out->pix_clk_100hz / 10; + /* YCbCr 4:2:0 requires additional adjustment of 1/2 */ + if (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420) + normalized_clk /= 2; + /* Adjusting pix clock following on HDMI spec based on colour depth */ + switch (depth) { + case COLOR_DEPTH_888: + break; + case COLOR_DEPTH_101010: + normalized_clk = (normalized_clk * 30) / 24; + break; + case COLOR_DEPTH_121212: + normalized_clk = (normalized_clk * 36) / 24; + break; + case COLOR_DEPTH_161616: + normalized_clk = (normalized_clk * 48) / 24; + break; + default: + /* The above depths are the only ones valid for HDMI. */ + return false; + } + if (normalized_clk <= info->max_tmds_clock) { + timing_out->display_color_depth = depth; + return true; + } + } while (--depth > COLOR_DEPTH_666); + return false; +} +EXPORT_IF_KUNIT(adjust_colour_depth_from_display_info); + +static void fill_stream_properties_from_drm_display_mode( + struct dc_stream_state *stream, + const struct drm_display_mode *mode_in, + const struct drm_connector *connector, + const struct drm_connector_state *connector_state, + const struct dc_stream_state *old_stream, + int requested_bpc) +{ + bool is_dp_or_hdmi = dc_is_hdmi_signal(stream->signal) || dc_is_dp_signal(stream->signal); + struct dc_crtc_timing *timing_out = &stream->timing; + const struct drm_display_info *info = &connector->display_info; + struct amdgpu_dm_connector *aconnector = NULL; + struct hdmi_vendor_infoframe hv_frame; + struct hdmi_avi_infoframe avi_frame; + bool want_420; + bool want_422; + ssize_t err; + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + aconnector = to_amdgpu_dm_connector(connector); + + memset(&hv_frame, 0, sizeof(hv_frame)); + memset(&avi_frame, 0, sizeof(avi_frame)); + + timing_out->h_border_left = 0; + timing_out->h_border_right = 0; + timing_out->v_border_top = 0; + timing_out->v_border_bottom = 0; + + want_420 = (aconnector && aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR420) || + (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR420); + want_422 = (aconnector && aconnector->force_yuv_pixel_format == PIXEL_ENCODING_YCBCR422) || + (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR422); + + if (drm_mode_is_420_only(info, mode_in) && + (want_420 || connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO)) { + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; + } else if (drm_mode_is_420_also(info, mode_in) && want_420) { + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; + } else if ((info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422)) && + want_422 && is_dp_or_hdmi) { + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR422; + } else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_YCBCR444 && + (info->color_formats & BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444)) && + is_dp_or_hdmi) { + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; + } else if (connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_RGB444 || + connector_state->color_format == DRM_CONNECTOR_COLOR_FORMAT_AUTO) { + timing_out->pixel_encoding = PIXEL_ENCODING_RGB; + } else { + /* + * If a format was explicitly requested but the requested format + * can't be satisfied, set it to an invalid value so that an + * error bubbles up to userspace. This way, userspace knows it + * needs to make a better choice. + */ + if (connector_state->color_format != DRM_CONNECTOR_COLOR_FORMAT_AUTO) + timing_out->pixel_encoding = PIXEL_ENCODING_UNDEFINED; + else if (drm_mode_is_420_only(info, mode_in)) + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; + else + timing_out->pixel_encoding = PIXEL_ENCODING_RGB; + } + + timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE; + timing_out->display_color_depth = amdgpu_dm_convert_color_depth_from_display_info( + connector, + (timing_out->pixel_encoding == PIXEL_ENCODING_YCBCR420), + requested_bpc); + timing_out->scan_type = SCANNING_TYPE_NODATA; + timing_out->hdmi_vic = 0; + + if (old_stream) { + timing_out->vic = old_stream->timing.vic; + timing_out->flags.HSYNC_POSITIVE_POLARITY = old_stream->timing.flags.HSYNC_POSITIVE_POLARITY; + timing_out->flags.VSYNC_POSITIVE_POLARITY = old_stream->timing.flags.VSYNC_POSITIVE_POLARITY; + } else { + timing_out->vic = drm_match_cea_mode(mode_in); + if (mode_in->flags & DRM_MODE_FLAG_PHSYNC) + timing_out->flags.HSYNC_POSITIVE_POLARITY = 1; + if (mode_in->flags & DRM_MODE_FLAG_PVSYNC) + timing_out->flags.VSYNC_POSITIVE_POLARITY = 1; + } + + if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || + stream->signal == SIGNAL_TYPE_HDMI_FRL) { + err = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame, + (struct drm_connector *)connector, + mode_in); + if (err < 0) + drm_warn_once(connector->dev, "Failed to setup avi infoframe on connector %s: %zd\n", + connector->name, err); + timing_out->vic = avi_frame.video_code; + err = drm_hdmi_vendor_infoframe_from_display_mode(&hv_frame, + (struct drm_connector *)connector, + mode_in); + if (err < 0) + drm_warn_once(connector->dev, "Failed to setup vendor infoframe on connector %s: %zd\n", + connector->name, err); + timing_out->hdmi_vic = hv_frame.vic; + } + + if (aconnector && amdgpu_dm_is_freesync_video_mode(mode_in, aconnector)) { + timing_out->h_addressable = mode_in->hdisplay; + timing_out->h_total = mode_in->htotal; + timing_out->h_sync_width = mode_in->hsync_end - mode_in->hsync_start; + timing_out->h_front_porch = mode_in->hsync_start - mode_in->hdisplay; + timing_out->v_total = mode_in->vtotal; + timing_out->v_addressable = mode_in->vdisplay; + timing_out->v_front_porch = mode_in->vsync_start - mode_in->vdisplay; + timing_out->v_sync_width = mode_in->vsync_end - mode_in->vsync_start; + timing_out->pix_clk_100hz = mode_in->clock * 10; + } else { + timing_out->h_addressable = mode_in->crtc_hdisplay; + timing_out->h_total = mode_in->crtc_htotal; + timing_out->h_sync_width = mode_in->crtc_hsync_end - mode_in->crtc_hsync_start; + timing_out->h_front_porch = mode_in->crtc_hsync_start - mode_in->crtc_hdisplay; + timing_out->v_total = mode_in->crtc_vtotal; + timing_out->v_addressable = mode_in->crtc_vdisplay; + timing_out->v_front_porch = mode_in->crtc_vsync_start - mode_in->crtc_vdisplay; + timing_out->v_sync_width = mode_in->crtc_vsync_end - mode_in->crtc_vsync_start; + timing_out->pix_clk_100hz = mode_in->crtc_clock * 10; + } + + timing_out->aspect_ratio = get_aspect_ratio(mode_in); + + stream->out_transfer_func.type = TF_TYPE_PREDEFINED; + stream->out_transfer_func.tf = TRANSFER_FUNCTION_SRGB; + if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) { + if (!adjust_colour_depth_from_display_info(timing_out, info) && + drm_mode_is_420_also(info, mode_in) && + timing_out->pixel_encoding != PIXEL_ENCODING_YCBCR420) { + timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; + adjust_colour_depth_from_display_info(timing_out, info); + } + } + + stream->output_color_space = amdgpu_dm_get_output_color_space(timing_out, connector_state); + stream->content_type = get_output_content_type(connector_state); +} + +static void +copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode *src_mode, + struct drm_display_mode *dst_mode) +{ + dst_mode->crtc_hdisplay = src_mode->crtc_hdisplay; + dst_mode->crtc_vdisplay = src_mode->crtc_vdisplay; + dst_mode->crtc_clock = src_mode->crtc_clock; + dst_mode->crtc_hblank_start = src_mode->crtc_hblank_start; + dst_mode->crtc_hblank_end = src_mode->crtc_hblank_end; + dst_mode->crtc_hsync_start = src_mode->crtc_hsync_start; + dst_mode->crtc_hsync_end = src_mode->crtc_hsync_end; + dst_mode->crtc_htotal = src_mode->crtc_htotal; + dst_mode->crtc_hskew = src_mode->crtc_hskew; + dst_mode->crtc_vblank_start = src_mode->crtc_vblank_start; + dst_mode->crtc_vblank_end = src_mode->crtc_vblank_end; + dst_mode->crtc_vsync_start = src_mode->crtc_vsync_start; + dst_mode->crtc_vsync_end = src_mode->crtc_vsync_end; + dst_mode->crtc_vtotal = src_mode->crtc_vtotal; +} + +STATIC_IFN_KUNIT void +decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode, + const struct drm_display_mode *native_mode, + bool scale_enabled) +{ + if (scale_enabled || ( + native_mode->clock == drm_mode->clock && + native_mode->htotal == drm_mode->htotal && + native_mode->vtotal == drm_mode->vtotal)) { + if (native_mode->crtc_clock) + copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode); + } else { + /* no scaling nor amdgpu inserted, no need to patch */ + } +} +EXPORT_IF_KUNIT(decide_crtc_timing_for_drm_display_mode); + +static struct dc_sink * +create_fake_sink(struct drm_device *dev, struct dc_link *link) +{ + struct dc_sink_init_data sink_init_data = { 0 }; + struct dc_sink *sink = NULL; + + sink_init_data.link = link; + sink_init_data.sink_signal = link->connector_signal; + + sink = dc_sink_create(&sink_init_data); + if (!sink) { + drm_err(dev, "Failed to create sink!\n"); + return NULL; + } + sink->sink_signal = SIGNAL_TYPE_VIRTUAL; + + return sink; +} + +/** + * DOC: FreeSync Video + * + * When a userspace application wants to play a video, the content follows a + * standard format definition that usually specifies the FPS for that format. + * The below list illustrates some video format and the expected FPS, + * respectively: + * + * - TV/NTSC (23.976 FPS) + * - Cinema (24 FPS) + * - TV/PAL (25 FPS) + * - TV/NTSC (29.97 FPS) + * - TV/NTSC (30 FPS) + * - Cinema HFR (48 FPS) + * - TV/PAL (50 FPS) + * - Commonly used (60 FPS) + * - Multiples of 24 (48,72,96 FPS) + * + * The list of standards video format is not huge and can be added to the + * connector modeset list beforehand. With that, userspace can leverage + * FreeSync to extends the front porch in order to attain the target refresh + * rate. Such a switch will happen seamlessly, without screen blanking or + * reprogramming of the output in any other way. If the userspace requests a + * modesetting change compatible with FreeSync modes that only differ in the + * refresh rate, DC will skip the full update and avoid blink during the + * transition. For example, the video player can change the modesetting from + * 60Hz to 30Hz for playing TV/NTSC content when it goes full screen without + * causing any display blink. This same concept can be applied to a mode + * setting change. + */ +struct drm_display_mode * +amdgpu_dm_get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector, + bool use_probed_modes) +{ + struct drm_display_mode *m, *m_pref = NULL; + u16 current_refresh, highest_refresh; + struct list_head *list_head = use_probed_modes ? + &aconnector->base.probed_modes : + &aconnector->base.modes; + + if (aconnector->base.connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return NULL; + + if (aconnector->freesync_vid_base.clock != 0) + return &aconnector->freesync_vid_base; + + /* Find the preferred mode */ + list_for_each_entry(m, list_head, head) { + if (m->type & DRM_MODE_TYPE_PREFERRED) { + m_pref = m; + break; + } + } + + if (!m_pref) { + /* Probably an EDID with no preferred mode. Fallback to first entry */ + m_pref = list_first_entry_or_null( + &aconnector->base.modes, struct drm_display_mode, head); + if (!m_pref) { + drm_dbg_driver(aconnector->base.dev, "No preferred mode found in EDID\n"); + return NULL; + } + } + + highest_refresh = drm_mode_vrefresh(m_pref); + + /* + * Find the mode with highest refresh rate with same resolution. + * For some monitors, preferred mode is not the mode with highest + * supported refresh rate. + */ + list_for_each_entry(m, list_head, head) { + current_refresh = drm_mode_vrefresh(m); + + if (m->hdisplay == m_pref->hdisplay && + m->vdisplay == m_pref->vdisplay && + highest_refresh < current_refresh) { + highest_refresh = current_refresh; + m_pref = m; + } + } + + drm_mode_copy(&aconnector->freesync_vid_base, m_pref); + return m_pref; +} +EXPORT_IF_KUNIT(amdgpu_dm_get_highest_refresh_rate_mode); + +bool amdgpu_dm_is_freesync_video_mode(const struct drm_display_mode *mode, + struct amdgpu_dm_connector *aconnector) +{ + struct drm_display_mode *high_mode; + int timing_diff; + + high_mode = amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false); + if (!high_mode || !mode) + return false; + + timing_diff = high_mode->vtotal - mode->vtotal; + + if (high_mode->clock == 0 || high_mode->clock != mode->clock || + high_mode->hdisplay != mode->hdisplay || + high_mode->vdisplay != mode->vdisplay || + high_mode->hsync_start != mode->hsync_start || + high_mode->hsync_end != mode->hsync_end || + high_mode->htotal != mode->htotal || + high_mode->hskew != mode->hskew || + high_mode->vscan != mode->vscan || + high_mode->vsync_start - mode->vsync_start != timing_diff || + high_mode->vsync_end - mode->vsync_end != timing_diff) + return false; + else + return true; +} +EXPORT_IF_KUNIT(amdgpu_dm_is_freesync_video_mode); + +#if defined(CONFIG_DRM_AMD_DC_FP) +static void update_dsc_caps(struct amdgpu_dm_connector *aconnector, + struct dc_sink *sink, struct dc_stream_state *stream, + struct dsc_dec_dpcd_caps *dsc_caps) +{ + stream->timing.flags.DSC = 0; + dsc_caps->is_dsc_supported = false; + + if (aconnector->dc_link && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT || + sink->sink_signal == SIGNAL_TYPE_EDP)) { + if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) + dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, + aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, + aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, + dsc_caps); + else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) { + if (aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT && + !aconnector->dsc_settings.dsc_force_disable_passthrough && + aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps > 0 && + sink->edid_caps.frl_dsc_support && + sink->edid_caps.max_frl_rate > 0 && + sink->edid_caps.frl_dsc_max_frl_rate > 0) + dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps); + else + dc_dsc_parse_dsc_dpcd(aconnector->dc_link->ctx->dc, + aconnector->dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.raw, + aconnector->dc_link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw, + dsc_caps); + } + } else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) { + if (sink->edid_caps.frl_dsc_support && + sink->edid_caps.max_frl_rate > 0 && + sink->edid_caps.frl_dsc_max_frl_rate > 0) + dc_dsc_parse_dsc_edid(aconnector->dc_link->ctx->dc, &sink->edid_caps, dsc_caps); + } +} + +static void apply_dsc_policy_for_edp(struct amdgpu_dm_connector *aconnector, + struct dc_sink *sink, struct dc_stream_state *stream, + struct dsc_dec_dpcd_caps *dsc_caps, + uint32_t max_dsc_target_bpp_limit_override) +{ + const struct dc_link_settings *verified_link_cap = NULL; + u32 link_bw_in_kbps; + u32 edp_min_bpp_x16, edp_max_bpp_x16; + struct dc *dc = sink->ctx->dc; + struct dc_dsc_bw_range bw_range = {0}; + struct dc_dsc_config dsc_cfg = {0}; + struct dc_dsc_config_options dsc_options = {0}; + + dc_dsc_get_default_config_option(dc, &dsc_options); + dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16; + + verified_link_cap = dc_link_get_link_cap(stream->link); + link_bw_in_kbps = dc_link_bandwidth_kbps(stream->link, verified_link_cap); + edp_min_bpp_x16 = 8 * 16; + edp_max_bpp_x16 = 8 * 16; + + if (edp_max_bpp_x16 > dsc_caps->edp_max_bits_per_pixel) + edp_max_bpp_x16 = dsc_caps->edp_max_bits_per_pixel; + + if (edp_max_bpp_x16 < edp_min_bpp_x16) + edp_min_bpp_x16 = edp_max_bpp_x16; + + if (dc_dsc_compute_bandwidth_range(dc->res_pool->dscs[0], + dc->debug.dsc_min_slice_height_override, + edp_min_bpp_x16, edp_max_bpp_x16, + dsc_caps, + &stream->timing, + dc_link_get_highest_encoding_format(aconnector->dc_link), + &bw_range)) { + + if (bw_range.max_kbps < link_bw_in_kbps) { + if (dc_dsc_compute_config(dc->res_pool->dscs[0], + dsc_caps, + &dsc_options, + 0, + &stream->timing, + dc_link_get_highest_encoding_format(aconnector->dc_link), + &dsc_cfg)) { + stream->timing.dsc_cfg = dsc_cfg; + stream->timing.flags.DSC = 1; + stream->timing.dsc_cfg.bits_per_pixel = edp_max_bpp_x16; + } + return; + } + } + + if (dc_dsc_compute_config(dc->res_pool->dscs[0], + dsc_caps, + &dsc_options, + link_bw_in_kbps, + &stream->timing, + dc_link_get_highest_encoding_format(aconnector->dc_link), + &dsc_cfg)) { + stream->timing.dsc_cfg = dsc_cfg; + stream->timing.flags.DSC = 1; + } +} + +static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector, + struct dc_sink *sink, struct dc_stream_state *stream, + struct dsc_dec_dpcd_caps *dsc_caps) +{ + struct drm_connector *drm_connector = &aconnector->base; + u32 link_bandwidth_kbps; + struct dc *dc = sink->ctx->dc; + const struct dc_hdmi_frl_link_settings *frl_verified_link_cap = NULL; + u32 converter_bw_in_kbps; + u32 sink_bw_in_kbps; + u32 dsc_sink_bw_in_kbps; + u32 max_supported_bw_in_kbps, timing_bw_in_kbps; + u32 dsc_max_supported_bw_in_kbps; + u32 max_dsc_target_bpp_limit_override = + drm_connector->display_info.max_dsc_bpp; + struct dc_dsc_config_options dsc_options = {0}; + + dc_dsc_get_default_config_option(dc, &dsc_options); + dsc_options.max_target_bpp_limit_override_x16 = max_dsc_target_bpp_limit_override * 16; + + link_bandwidth_kbps = dc_link_bandwidth_kbps(aconnector->dc_link, + dc_link_get_link_cap(aconnector->dc_link)); + + /* Set DSC policy according to dsc_clock_en */ + dc_dsc_policy_set_enable_dsc_when_not_needed( + aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE); + + if (sink->sink_signal == SIGNAL_TYPE_EDP && + !aconnector->dc_link->panel_config.dsc.disable_dsc_edp && + dc->caps.edp_dsc_support && aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE) { + + apply_dsc_policy_for_edp(aconnector, sink, stream, dsc_caps, max_dsc_target_bpp_limit_override); + + } else if (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT) { + if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_NONE) { + if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], + dsc_caps, + &dsc_options, + link_bandwidth_kbps, + &stream->timing, + dc_link_get_highest_encoding_format(aconnector->dc_link), + &stream->timing.dsc_cfg)) { + stream->timing.flags.DSC = 1; + drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from SST RX\n", + __func__, drm_connector->name); + } + } else if (sink->link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER) { + timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing, + dc_link_get_highest_encoding_format(aconnector->dc_link)); + converter_bw_in_kbps = aconnector->dc_link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps; + sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.max_frl_rate); + dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate); + + if (dsc_caps->is_frl) { + max_supported_bw_in_kbps = min(link_bandwidth_kbps, converter_bw_in_kbps); + max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, sink_bw_in_kbps); + dsc_max_supported_bw_in_kbps = min(max_supported_bw_in_kbps, dsc_sink_bw_in_kbps); + } else { + max_supported_bw_in_kbps = link_bandwidth_kbps; + dsc_max_supported_bw_in_kbps = link_bandwidth_kbps; + } + + if (timing_bw_in_kbps > max_supported_bw_in_kbps && + max_supported_bw_in_kbps > 0 && + dsc_max_supported_bw_in_kbps > 0) + if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], + dsc_caps, + &dsc_options, + dsc_max_supported_bw_in_kbps, + &stream->timing, + dc_link_get_highest_encoding_format(aconnector->dc_link), + &stream->timing.dsc_cfg)) { + stream->timing.flags.DSC = 1; + drm_dbg_driver(drm_connector->dev, "%s: SST_DSC [%s] DSC is selected from %s\n", + __func__, drm_connector->name, + (dsc_caps->is_frl == 1) ? "HDMI FRL RX" : "DP-HDMI PCON"); + } + } + } else if (aconnector->dc_link && sink->sink_signal == SIGNAL_TYPE_HDMI_FRL) { + struct dc_dsc_policy dsc_policy = {0}; + + frl_verified_link_cap = dc_link_get_frl_link_cap(stream->link); + if (frl_verified_link_cap->frl_link_rate != HDMI_FRL_LINK_RATE_DISABLE && + aconnector->dc_link->frl_flags.force_frl_dsc) { + dc_dsc_policy_set_enable_dsc_when_not_needed(true); + dc_dsc_get_policy_for_timing(&stream->timing, 0, &dsc_policy, dc_link_get_highest_encoding_format(stream->link)); + } + + timing_bw_in_kbps = dc_bandwidth_in_kbps_from_timing(&stream->timing, DC_LINK_ENCODING_HDMI_FRL); + link_bandwidth_kbps = dc_link_frl_bandwidth_kbps(stream->link, frl_verified_link_cap->frl_link_rate); + dsc_sink_bw_in_kbps = dc_link_bw_kbps_from_raw_frl_link_rate_data(dc, sink->edid_caps.frl_dsc_max_frl_rate); + + if ((timing_bw_in_kbps > link_bandwidth_kbps && dsc_sink_bw_in_kbps > 0) || + (dsc_policy.enable_dsc_when_not_needed || dsc_options.force_dsc_when_not_needed)) { + if (dc_dsc_compute_config(aconnector->dc_link->ctx->dc->res_pool->dscs[0], + dsc_caps, + &dsc_options, + dsc_sink_bw_in_kbps, + &stream->timing, + dc_link_get_highest_encoding_format(aconnector->dc_link), + &stream->timing.dsc_cfg)) { + stream->timing.flags.DSC = 1; + drm_dbg_driver(drm_connector->dev, "%s: HDMI_FRL_DSC [%s] DSC is selected from HDMI FRL RX\n", + __func__, drm_connector->name); + } + } + } + + /* Overwrite the stream flag if DSC is enabled through debugfs */ + if (aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE) + stream->timing.flags.DSC = 1; + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_h) + stream->timing.dsc_cfg.num_slices_h = aconnector->dsc_settings.dsc_num_slices_h; + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_num_slices_v) + stream->timing.dsc_cfg.num_slices_v = aconnector->dsc_settings.dsc_num_slices_v; + + if (stream->timing.flags.DSC && aconnector->dsc_settings.dsc_bits_per_pixel) + stream->timing.dsc_cfg.bits_per_pixel = aconnector->dsc_settings.dsc_bits_per_pixel; +} +#endif + +static struct dc_stream_state * +create_stream_for_sink(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + const struct dm_connector_state *dm_state, + const struct dc_stream_state *old_stream, + int requested_bpc) +{ + struct drm_device *dev = connector->dev; + struct amdgpu_dm_connector *aconnector = NULL; + struct drm_display_mode *preferred_mode = NULL; + const struct drm_connector_state *con_state = &dm_state->base; + struct dc_stream_state *stream = NULL; + struct drm_display_mode mode; + struct drm_display_mode saved_mode; + struct drm_display_mode *freesync_mode = NULL; + bool native_mode_found = false; + bool recalculate_timing = false; + bool scale = dm_state->scaling != RMX_OFF; + int mode_refresh; + int preferred_refresh = 0; + enum color_transfer_func tf = TRANSFER_FUNC_UNKNOWN; +#if defined(CONFIG_DRM_AMD_DC_FP) + struct dsc_dec_dpcd_caps dsc_caps = {0}; +#endif + struct dc_link *link = NULL; + struct dc_sink *sink = NULL; + + drm_mode_init(&mode, drm_mode); + memset(&saved_mode, 0, sizeof(saved_mode)); + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) { + aconnector = NULL; + aconnector = to_amdgpu_dm_connector(connector); + link = aconnector->dc_link; + } else { + struct drm_writeback_connector *wbcon = NULL; + struct amdgpu_dm_wb_connector *dm_wbcon = NULL; + + wbcon = drm_connector_to_writeback(connector); + dm_wbcon = to_amdgpu_dm_wb_connector(wbcon); + link = dm_wbcon->link; + } + + if (!aconnector || !aconnector->dc_sink) { + sink = create_fake_sink(dev, link); + if (!sink) + return stream; + + } else { + sink = aconnector->dc_sink; + dc_sink_retain(sink); + } + + stream = dc_create_stream_for_sink(sink); + + if (stream == NULL) { + drm_err(dev, "Failed to create stream for sink!\n"); + goto finish; + } + + /* We leave this NULL for writeback connectors */ + stream->dm_stream_context = aconnector; + + stream->timing.flags.LTE_340MCSC_SCRAMBLE = + connector->display_info.hdmi.scdc.scrambling.low_rates; + + list_for_each_entry(preferred_mode, &connector->modes, head) { + /* Search for preferred mode */ + if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) { + native_mode_found = true; + break; + } + } + if (!native_mode_found) + preferred_mode = list_first_entry_or_null( + &connector->modes, + struct drm_display_mode, + head); + + mode_refresh = drm_mode_vrefresh(&mode); + + if (preferred_mode == NULL) { + /* + * This may not be an error, the use case is when we have no + * usermode calls to reset and set mode upon hotplug. In this + * case, we call set mode ourselves to restore the previous mode + * and the modelist may not be filled in time. + */ + drm_dbg_driver(dev, "No preferred mode found\n"); + } else if (aconnector) { + recalculate_timing = amdgpu_freesync_vid_mode && + amdgpu_dm_is_freesync_video_mode(&mode, aconnector); + if (recalculate_timing) { + freesync_mode = amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false); + drm_mode_copy(&saved_mode, &mode); + saved_mode.picture_aspect_ratio = mode.picture_aspect_ratio; + drm_mode_copy(&mode, freesync_mode); + mode.picture_aspect_ratio = saved_mode.picture_aspect_ratio; + } else { + decide_crtc_timing_for_drm_display_mode( + &mode, preferred_mode, scale); + + preferred_refresh = drm_mode_vrefresh(preferred_mode); + } + } + + if (recalculate_timing) + drm_mode_set_crtcinfo(&saved_mode, 0); + + /* + * If scaling is enabled and refresh rate didn't change + * we copy the vic and polarities of the old timings + */ + if (!scale || mode_refresh != preferred_refresh) + fill_stream_properties_from_drm_display_mode( + stream, &mode, connector, con_state, NULL, + requested_bpc); + else + fill_stream_properties_from_drm_display_mode( + stream, &mode, connector, con_state, old_stream, + requested_bpc); + + /* The rest isn't needed for writeback connectors */ + if (!aconnector) + goto finish; + + if (aconnector->timing_changed) { + drm_dbg(aconnector->base.dev, + "overriding timing for automated test, bpc %d, changing to %d\n", + stream->timing.display_color_depth, + aconnector->timing_requested->display_color_depth); + stream->timing = *aconnector->timing_requested; + } + +#if defined(CONFIG_DRM_AMD_DC_FP) + /* SST DSC determination policy */ + update_dsc_caps(aconnector, sink, stream, &dsc_caps); + if (aconnector->dsc_settings.dsc_force_enable != DSC_CLK_FORCE_DISABLE && dsc_caps.is_dsc_supported) + apply_dsc_policy_for_stream(aconnector, sink, stream, &dsc_caps); +#endif + + amdgpu_dm_update_stream_scaling_settings(dev, &mode, dm_state, stream); + + amdgpu_dm_fill_audio_info( + &stream->audio_info, + connector, + sink); + + update_stream_signal(stream, sink); + + if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || + stream->signal == SIGNAL_TYPE_HDMI_FRL) + mod_build_hf_vsif_infopacket(stream, &stream->vsp_infopacket, false, false); + + if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT || + stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + stream->signal == SIGNAL_TYPE_EDP) { + const struct dc_edid_caps *edid_caps; + unsigned int disable_colorimetry = 0; + + if (aconnector->dc_sink) { + edid_caps = &aconnector->dc_sink->edid_caps; + disable_colorimetry = edid_caps->panel_patch.disable_colorimetry; + } + + /* + * should decide stream support vsc sdp colorimetry capability + * before building vsc info packet + */ + stream->use_vsc_sdp_for_colorimetry = stream->link->dpcd_caps.dpcd_rev.raw >= 0x14 && + stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED && + !disable_colorimetry; + + if (stream->out_transfer_func.tf == TRANSFER_FUNCTION_GAMMA22) + tf = TRANSFER_FUNC_GAMMA_22; + mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space, tf); + aconnector->sr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY; + + } +finish: + dc_sink_release(sink); + + return stream; +} + +/** + * amdgpu_dm_connector_poll - Poll a connector to see if it's connected to a display + * @aconnector: DM connector to poll (owns @base drm_connector and @dc_link) + * @force: if true, force polling even when DAC load detection was used + * + * Used for connectors that don't support HPD (hotplug detection) to + * periodically check whether the connector is connected to a display. + * + * When connection was determined via DAC load detection, we avoid + * re-running it on normal polls to prevent visible glitches, unless + * @force is set. + * + * Return: The probed connector status (connected/disconnected/unknown). + */ +static enum drm_connector_status +amdgpu_dm_connector_poll(struct amdgpu_dm_connector *aconnector, bool force) +{ + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + struct dc_link *link = aconnector->dc_link; + enum dc_connection_type conn_type = dc_connection_none; + enum drm_connector_status status = connector_status_disconnected; + + /* When we determined the connection using DAC load detection, + * do NOT poll the connector do detect disconnect because + * that would run DAC load detection again which can cause + * visible visual glitches. + * + * Only allow to poll such a connector again when forcing. + */ + if (!force && link->local_sink && link->type == dc_connection_analog_load) + return connector->status; + + mutex_lock(&aconnector->hpd_lock); + + if (dc_link_detect_connection_type(aconnector->dc_link, &conn_type) && + conn_type != dc_connection_none) { + mutex_lock(&adev->dm.dc_lock); + + /* Only call full link detection when a sink isn't created yet, + * ie. just when the display is plugged in, otherwise we risk flickering. + */ + if (link->local_sink || + dc_link_detect(link, DETECT_REASON_HPD)) + status = connector_status_connected; + + mutex_unlock(&adev->dm.dc_lock); + } + + if (connector->status != status) { + if (status == connector_status_disconnected) { + if (link->local_sink) + dc_sink_release(link->local_sink); + + link->local_sink = NULL; + link->dpcd_sink_count = 0; + link->type = dc_connection_none; + } + + amdgpu_dm_update_connector_after_detect(aconnector); + } + + mutex_unlock(&aconnector->hpd_lock); + return status; +} + +/** + * amdgpu_dm_connector_detect() - Detect whether a DRM connector is connected to a display + * + * A connector is considered connected when it has a sink that is not NULL. + * For connectors that support HPD (hotplug detection), the connection is + * handled in the HPD interrupt. + * For connectors that may not support HPD, such as analog connectors, + * DRM will call this function repeatedly to poll them. + * + * Notes: + * 1. This interface is NOT called in context of HPD irq. + * 2. This interface *is called* in context of user-mode ioctl. Which + * makes it a bad place for *any* MST-related activity. + * + * @connector: The DRM connector we are checking. We convert it to + * amdgpu_dm_connector so we can read the DC link and state. + * @force: If true, do a full detect again. This is used even when + * a lighter check would normally be used to avoid flicker. + * + * Return: The connector status (connected, disconnected, or unknown). + * + */ +static enum drm_connector_status +amdgpu_dm_connector_detect(struct drm_connector *connector, bool force) +{ + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + + update_subconnector_property(aconnector); + + if (aconnector->base.force == DRM_FORCE_ON || + aconnector->base.force == DRM_FORCE_ON_DIGITAL) + return connector_status_connected; + else if (aconnector->base.force == DRM_FORCE_OFF) + return connector_status_disconnected; + + /* Poll analog connectors and only when either + * disconnected or connected to an analog display. + */ + if (drm_kms_helper_is_poll_worker() && + dc_connector_supports_analog(aconnector->dc_link->link_id.id) && + (!aconnector->dc_sink || aconnector->dc_sink->edid_caps.analog)) + return amdgpu_dm_connector_poll(aconnector, force); + + return (aconnector->dc_sink ? connector_status_connected : + connector_status_disconnected); +} + +int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, + struct drm_connector_state *connector_state, + struct drm_property *property, + uint64_t val) +{ + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + struct dm_connector_state *dm_old_state = + to_dm_connector_state(connector->state); + struct dm_connector_state *dm_new_state = + to_dm_connector_state(connector_state); + + int ret = -EINVAL; + + if (property == dev->mode_config.scaling_mode_property) { + enum amdgpu_rmx_type rmx_type; + + switch (val) { + case DRM_MODE_SCALE_CENTER: + rmx_type = RMX_CENTER; + break; + case DRM_MODE_SCALE_ASPECT: + rmx_type = RMX_ASPECT; + break; + case DRM_MODE_SCALE_FULLSCREEN: + rmx_type = RMX_FULL; + break; + case DRM_MODE_SCALE_NONE: + default: + rmx_type = RMX_OFF; + break; + } + + if (dm_old_state->scaling == rmx_type) + return 0; + + dm_new_state->scaling = rmx_type; + ret = 0; + } else if (property == adev->mode_info.underscan_hborder_property) { + dm_new_state->underscan_hborder = val; + ret = 0; + } else if (property == adev->mode_info.underscan_vborder_property) { + dm_new_state->underscan_vborder = val; + ret = 0; + } else if (property == adev->mode_info.underscan_property) { + dm_new_state->underscan_enable = val; + ret = 0; + } else if (property == adev->mode_info.abm_level_property) { + switch (val) { + case ABM_SYSFS_CONTROL: + dm_new_state->abm_sysfs_forbidden = false; + break; + case ABM_LEVEL_OFF: + dm_new_state->abm_sysfs_forbidden = true; + dm_new_state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE; + break; + default: + dm_new_state->abm_sysfs_forbidden = true; + dm_new_state->abm_level = val; + } + ret = 0; + } + + return ret; +} +EXPORT_IF_KUNIT(amdgpu_dm_connector_atomic_set_property); + +int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val) +{ + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + struct dm_connector_state *dm_state = + to_dm_connector_state(state); + int ret = -EINVAL; + + if (property == dev->mode_config.scaling_mode_property) { + switch (dm_state->scaling) { + case RMX_CENTER: + *val = DRM_MODE_SCALE_CENTER; + break; + case RMX_ASPECT: + *val = DRM_MODE_SCALE_ASPECT; + break; + case RMX_FULL: + *val = DRM_MODE_SCALE_FULLSCREEN; + break; + case RMX_OFF: + default: + *val = DRM_MODE_SCALE_NONE; + break; + } + ret = 0; + } else if (property == adev->mode_info.underscan_hborder_property) { + *val = dm_state->underscan_hborder; + ret = 0; + } else if (property == adev->mode_info.underscan_vborder_property) { + *val = dm_state->underscan_vborder; + ret = 0; + } else if (property == adev->mode_info.underscan_property) { + *val = dm_state->underscan_enable; + ret = 0; + } else if (property == adev->mode_info.abm_level_property) { + if (!dm_state->abm_sysfs_forbidden) + *val = ABM_SYSFS_CONTROL; + else + *val = (dm_state->abm_level != ABM_LEVEL_IMMEDIATE_DISABLE) ? + dm_state->abm_level : 0; + ret = 0; + } + + return ret; +} +EXPORT_IF_KUNIT(amdgpu_dm_connector_atomic_get_property); + +static void amdgpu_dm_connector_unregister(struct drm_connector *connector) +{ + struct amdgpu_dm_connector *amdgpu_dm_connector = to_amdgpu_dm_connector(connector); + + if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) + sysfs_remove_group(&connector->kdev->kobj, &amdgpu_group); + + cec_notifier_conn_unregister(amdgpu_dm_connector->notifier); + drm_dp_aux_unregister(&amdgpu_dm_connector->dm_dp_aux.aux); +} + +static void amdgpu_dm_connector_destroy(struct drm_connector *connector) +{ + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct amdgpu_device *adev = drm_to_adev(connector->dev); + struct amdgpu_display_manager *dm = &adev->dm; + + /* + * Call only if mst_mgr was initialized before since it's not done + * for all connector types. + */ + if (aconnector->mst_mgr.dev) + drm_dp_mst_topology_mgr_destroy(&aconnector->mst_mgr); + + /* Cancel and flush any pending HDMI HPD debounce work */ + if (aconnector->hdmi_hpd_debounce_delay_ms) { + cancel_delayed_work_sync(&aconnector->hdmi_hpd_debounce_work); + if (aconnector->hdmi_prev_sink) { + dc_sink_release(aconnector->hdmi_prev_sink); + aconnector->hdmi_prev_sink = NULL; + } + } + + if (aconnector->bl_idx != -1) { + backlight_device_unregister(dm->backlight_dev[aconnector->bl_idx]); + dm->backlight_dev[aconnector->bl_idx] = NULL; + } + + if (aconnector->dc_em_sink) + dc_sink_release(aconnector->dc_em_sink); + aconnector->dc_em_sink = NULL; + if (aconnector->dc_sink) + dc_sink_release(aconnector->dc_sink); + aconnector->dc_sink = NULL; + + drm_dp_cec_unregister_connector(&aconnector->dm_dp_aux.aux); + drm_connector_unregister(connector); + drm_connector_cleanup(connector); + kfree(aconnector->dm_dp_aux.aux.name); + + kfree(connector); +} + +void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector) +{ + struct dm_connector_state *old_state = + to_dm_connector_state(connector->state); + struct dm_connector_state *state; + + state = kzalloc_obj(*state); + if (!state) + return; + + if (connector->state) + __drm_atomic_helper_connector_destroy_state(connector->state); + + kfree(old_state); + + __drm_atomic_helper_connector_reset(connector, &state->base); + + state->scaling = RMX_OFF; + state->underscan_enable = false; + state->underscan_hborder = 0; + state->underscan_vborder = 0; + state->base.max_requested_bpc = 8; + state->vcpi_slots = 0; + state->pbn = 0; + + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + if (amdgpu_dm_abm_level <= 0) + state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE; + else + state->abm_level = amdgpu_dm_abm_level; + } +} +EXPORT_IF_KUNIT(amdgpu_dm_connector_funcs_reset); + +struct drm_connector_state * +amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector) +{ + struct dm_connector_state *state = + to_dm_connector_state(connector->state); + + struct dm_connector_state *new_state = + kmemdup(state, sizeof(*state), GFP_KERNEL); + + if (!new_state) + return NULL; + + __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); + + new_state->freesync_capable = state->freesync_capable; + new_state->abm_level = state->abm_level; + new_state->scaling = state->scaling; + new_state->underscan_enable = state->underscan_enable; + new_state->underscan_hborder = state->underscan_hborder; + new_state->underscan_vborder = state->underscan_vborder; + new_state->vcpi_slots = state->vcpi_slots; + new_state->pbn = state->pbn; + return &new_state->base; +} +EXPORT_IF_KUNIT(amdgpu_dm_connector_atomic_duplicate_state); + +static int +amdgpu_dm_connector_late_register(struct drm_connector *connector) +{ + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + int r; + + if (amdgpu_dm_should_create_sysfs(amdgpu_dm_connector)) { + r = sysfs_create_group(&connector->kdev->kobj, + &amdgpu_group); + if (r) + return r; + } + + amdgpu_dm_register_backlight_device(amdgpu_dm_connector); + + if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) || + (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { + amdgpu_dm_connector->dm_dp_aux.aux.dev = connector->kdev; + r = drm_dp_aux_register(&amdgpu_dm_connector->dm_dp_aux.aux); + if (r) + return r; + } + +#if defined(CONFIG_DEBUG_FS) + connector_debugfs_init(amdgpu_dm_connector); +#endif + + return 0; +} + +static void amdgpu_dm_connector_funcs_force(struct drm_connector *connector) +{ + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + struct dc_link *dc_link = aconnector->dc_link; + struct dc_sink *dc_em_sink = aconnector->dc_em_sink; + const struct drm_edid *drm_edid; + struct i2c_adapter *ddc; + struct drm_device *dev = connector->dev; + + if (dc_link && dc_link->aux_mode) + ddc = &aconnector->dm_dp_aux.aux.ddc; + else + ddc = &aconnector->i2c->base; + + drm_edid = drm_edid_read_ddc(connector, ddc); + drm_edid_connector_update(connector, drm_edid); + if (!drm_edid) { + drm_err(dev, "No EDID found on connector: %s.\n", connector->name); + return; + } + + aconnector->drm_edid = drm_edid; + /* Update emulated (virtual) sink's EDID */ + if (dc_em_sink && dc_link) { + /* FIXME: Get rid of drm_edid_raw() */ + const struct edid *edid = drm_edid_raw(drm_edid); + + memset(&dc_em_sink->edid_caps, 0, sizeof(struct dc_edid_caps)); + memmove(dc_em_sink->dc_edid.raw_edid, edid, + (edid->extensions + 1) * EDID_LENGTH); + dm_helpers_parse_edid_caps( + dc_link, + &dc_em_sink->dc_edid, + &dc_em_sink->edid_caps); + } +} + +static const struct drm_connector_funcs amdgpu_dm_connector_funcs = { + .reset = amdgpu_dm_connector_funcs_reset, + .detect = amdgpu_dm_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = amdgpu_dm_connector_destroy, + .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_set_property = amdgpu_dm_connector_atomic_set_property, + .atomic_get_property = amdgpu_dm_connector_atomic_get_property, + .late_register = amdgpu_dm_connector_late_register, + .early_unregister = amdgpu_dm_connector_unregister, + .force = amdgpu_dm_connector_funcs_force +}; + +static int get_modes(struct drm_connector *connector) +{ + return amdgpu_dm_connector_get_modes(connector); +} + +static void create_eml_sink(struct amdgpu_dm_connector *aconnector) +{ + struct drm_connector *connector = &aconnector->base; + struct dc_link *dc_link = aconnector->dc_link; + struct dc_sink_init_data init_params = { + .link = aconnector->dc_link, + .sink_signal = SIGNAL_TYPE_VIRTUAL + }; + const struct drm_edid *drm_edid; + const struct edid *edid; + struct i2c_adapter *ddc; + + if (dc_link && dc_link->aux_mode) + ddc = &aconnector->dm_dp_aux.aux.ddc; + else + ddc = &aconnector->i2c->base; + + drm_edid = drm_edid_read_ddc(connector, ddc); + drm_edid_connector_update(connector, drm_edid); + if (!drm_edid) { + drm_err(connector->dev, "No EDID found on connector: %s.\n", connector->name); + return; + } + + if (connector->display_info.is_hdmi) + init_params.sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + + aconnector->drm_edid = drm_edid; + + /* FIXME: Get rid of drm_edid_raw() */ + edid = drm_edid_raw(drm_edid); + aconnector->dc_em_sink = dc_link_add_remote_sink( + aconnector->dc_link, + (uint8_t *)edid, + (edid->extensions + 1) * EDID_LENGTH, + &init_params); + + if (aconnector->base.force == DRM_FORCE_ON) { + aconnector->dc_sink = aconnector->dc_link->local_sink ? + aconnector->dc_link->local_sink : + aconnector->dc_em_sink; + if (aconnector->dc_sink) + dc_sink_retain(aconnector->dc_sink); + } +} + +static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector) +{ + struct dc_link *link = (struct dc_link *)aconnector->dc_link; + + /* + * In case of headless boot with force on for DP managed connector + * Those settings have to be != 0 to get initial modeset + */ + if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) { + link->verified_link_cap.lane_count = LANE_COUNT_FOUR; + link->verified_link_cap.link_rate = LINK_RATE_HIGH2; + } + + create_eml_sink(aconnector); +} + +static enum dc_status dm_validate_stream_and_context(struct dc *dc, + struct dc_stream_state *stream) +{ + enum dc_status dc_result = DC_ERROR_UNEXPECTED; + struct dc_plane_state *dc_plane_state = NULL; + struct dc_state *dc_state = NULL; + + if (!stream) + goto cleanup; + + dc_plane_state = dc_create_plane_state(dc); + if (!dc_plane_state) + goto cleanup; + + dc_state = dc_state_create(dc, NULL); + if (!dc_state) + goto cleanup; + + /* populate stream to plane */ + dc_plane_state->src_rect.height = stream->src.height; + dc_plane_state->src_rect.width = stream->src.width; + dc_plane_state->dst_rect.height = stream->src.height; + dc_plane_state->dst_rect.width = stream->src.width; + dc_plane_state->clip_rect.height = stream->src.height; + dc_plane_state->clip_rect.width = stream->src.width; + dc_plane_state->plane_size.surface_pitch = ((stream->src.width + 255) / 256) * 256; + dc_plane_state->plane_size.surface_size.height = stream->src.height; + dc_plane_state->plane_size.surface_size.width = stream->src.width; + dc_plane_state->plane_size.chroma_size.height = stream->src.height; + dc_plane_state->plane_size.chroma_size.width = stream->src.width; + dc_plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888; + dc_plane_state->tiling_info.gfx9.swizzle = DC_SW_UNKNOWN; + dc_plane_state->rotation = ROTATION_ANGLE_0; + dc_plane_state->is_tiling_rotated = false; + dc_plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_LINEAR_GENERAL; + + dc_result = dc_validate_stream(dc, stream); + if (dc_result == DC_OK) + dc_result = dc_validate_plane(dc, dc_plane_state); + + if (dc_result == DC_OK) + dc_result = dc_state_add_stream(dc, dc_state, stream); + + if (dc_result == DC_OK && !dc_state_add_plane( + dc, + stream, + dc_plane_state, + dc_state)) + dc_result = DC_FAIL_ATTACH_SURFACES; + + if (dc_result == DC_OK) + dc_result = dc_validate_global_state(dc, dc_state, DC_VALIDATE_MODE_ONLY); + +cleanup: + if (dc_state) + dc_state_release(dc_state); + + if (dc_plane_state) + dc_plane_state_release(dc_plane_state); + + return dc_result; +} + +static enum dc_status +dm_validate_stream_color_format(const struct drm_connector_state *drm_state, + const struct dc_stream_state *stream) +{ + enum dc_pixel_encoding encoding; + + if (!drm_state->color_format) + return DC_OK; + + switch (drm_state->color_format) { + case DRM_CONNECTOR_COLOR_FORMAT_AUTO: + case DRM_CONNECTOR_COLOR_FORMAT_RGB444: + encoding = PIXEL_ENCODING_RGB; + break; + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR444: + encoding = PIXEL_ENCODING_YCBCR444; + break; + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR422: + encoding = PIXEL_ENCODING_YCBCR422; + break; + case DRM_CONNECTOR_COLOR_FORMAT_YCBCR420: + encoding = PIXEL_ENCODING_YCBCR420; + break; + default: + encoding = PIXEL_ENCODING_UNDEFINED; + break; + } + + return encoding == stream->timing.pixel_encoding ? + DC_OK : DC_UNSUPPORTED_VALUE; +} + +struct dc_stream_state * +amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + const struct dm_connector_state *dm_state, + const struct dc_stream_state *old_stream) +{ + struct amdgpu_dm_connector *aconnector = NULL; + struct amdgpu_device *adev = drm_to_adev(connector->dev); + struct dc_stream_state *stream; + const struct drm_connector_state *drm_state = dm_state ? &dm_state->base : NULL; + int requested_bpc = drm_state ? drm_state->max_requested_bpc : 8; + enum dc_status dc_result = DC_OK; + uint8_t bpc_limit = 6; + + if (!dm_state) + return NULL; + + if (connector->connector_type != DRM_MODE_CONNECTOR_WRITEBACK) + aconnector = to_amdgpu_dm_connector(connector); + + if (aconnector && + (aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_TYPE_A || + aconnector->dc_link->connector_signal == SIGNAL_TYPE_HDMI_FRL || + aconnector->dc_link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER)) + bpc_limit = 8; + + do { + drm_dbg_kms(connector->dev, "Trying with %d bpc\n", requested_bpc); + stream = create_stream_for_sink(connector, drm_mode, + dm_state, old_stream, + requested_bpc); + if (stream == NULL) { + drm_err(adev_to_drm(adev), "Failed to create stream for sink!\n"); + break; + } + + dc_result = dc_validate_stream(adev->dm.dc, stream); + + if (!aconnector) /* writeback connector */ + return stream; + + if (dc_result == DC_OK && stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) + dc_result = dm_dp_mst_is_port_support_mode(aconnector, stream); + + if (dc_result == DC_OK) + dc_result = dm_validate_stream_and_context(adev->dm.dc, stream); + + if (dc_result == DC_OK) + dc_result = dm_validate_stream_color_format(drm_state, stream); + + if (dc_result != DC_OK) { + drm_dbg_kms(connector->dev, "Pruned mode %d x %d (clk %d) %s %s -- %s\n", + drm_mode->hdisplay, + drm_mode->vdisplay, + drm_mode->clock, + dc_pixel_encoding_to_str(stream->timing.pixel_encoding), + dc_color_depth_to_str(stream->timing.display_color_depth), + dc_status_to_str(dc_result)); + + dc_stream_release(stream); + stream = NULL; + requested_bpc -= 2; /* lower bpc to retry validation */ + } + + } while (stream == NULL && requested_bpc >= bpc_limit); + + switch (dc_result) { + /* + * If we failed to validate DP bandwidth stream with the requested RGB color depth, + * we try to fallback and configure in order: + * YUV422 (8bpc, 6bpc) + * YUV420 (8bpc, 6bpc) + */ + case DC_FAIL_ENC_VALIDATE: + case DC_EXCEED_DONGLE_CAP: + case DC_NO_DP_LINK_BANDWIDTH: + /* recursively entered twice and already tried both YUV422 and YUV420 */ + if (aconnector->force_yuv422_output && aconnector->force_yuv420_output) + break; + /* first failure; try YUV422 */ + if (!aconnector->force_yuv422_output) { + drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV422\n", + __func__, __LINE__, dc_result); + aconnector->force_yuv422_output = true; + /* recursively entered and YUV422 failed, try YUV420 */ + } else if (!aconnector->force_yuv420_output) { + drm_dbg_kms(connector->dev, "%s:%d Validation failed with %d, retrying w/ YUV420\n", + __func__, __LINE__, dc_result); + aconnector->force_yuv420_output = true; + } + stream = amdgpu_dm_create_validate_stream_for_sink(connector, drm_mode, + dm_state, old_stream); + aconnector->force_yuv422_output = false; + aconnector->force_yuv420_output = false; + break; + case DC_OK: + break; + default: + drm_dbg_kms(connector->dev, "%s:%d Unhandled validation failure %d\n", + __func__, __LINE__, dc_result); + break; + } + + return stream; +} + +enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode) +{ + int result = MODE_ERROR; + struct dc_sink *dc_sink; + struct drm_display_mode *test_mode; + /* TODO: Unhardcode stream count */ + struct dc_stream_state *stream; + /* we always have an amdgpu_dm_connector here since we got + * here via the amdgpu_dm_connector_helper_funcs + */ + struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); + + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) || + (mode->flags & DRM_MODE_FLAG_DBLSCAN)) + return result; + + /* + * Only run this the first time mode_valid is called to initilialize + * EDID mgmt + */ + if (aconnector->base.force != DRM_FORCE_UNSPECIFIED && + !aconnector->dc_em_sink) + handle_edid_mgmt(aconnector); + + dc_sink = to_amdgpu_dm_connector(connector)->dc_sink; + + if (dc_sink == NULL && aconnector->base.force != DRM_FORCE_ON_DIGITAL && + aconnector->base.force != DRM_FORCE_ON) { + drm_err(connector->dev, "dc_sink is NULL!\n"); + goto fail; + } + + test_mode = drm_mode_duplicate(connector->dev, mode); + if (!test_mode) + goto fail; + + drm_mode_set_crtcinfo(test_mode, 0); + + stream = amdgpu_dm_create_validate_stream_for_sink(connector, test_mode, + to_dm_connector_state(connector->state), + NULL); + drm_mode_destroy(connector->dev, test_mode); + if (stream) { + dc_stream_release(stream); + result = MODE_OK; + } + +fail: + /* TODO: error handling*/ + return result; +} + +int amdgpu_dm_fill_hdr_info_packet(const struct drm_connector_state *state, + struct dc_info_packet *out) +{ + struct hdmi_drm_infoframe frame; + unsigned char buf[30]; /* 26 + 4 */ + ssize_t len; + int ret, i; + + memset(out, 0, sizeof(*out)); + + if (!state->hdr_output_metadata) + return 0; + + ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, state); + if (ret) + return ret; + + len = hdmi_drm_infoframe_pack_only(&frame, buf, sizeof(buf)); + if (len < 0) + return (int)len; + + /* Static metadata is a fixed 26 bytes + 4 byte header. */ + if (len != 30) + return -EINVAL; + + /* Prepare the infopacket for DC. */ + switch (state->connector->connector_type) { + case DRM_MODE_CONNECTOR_HDMIA: + out->hb0 = 0x87; /* type */ + out->hb1 = 0x01; /* version */ + out->hb2 = 0x1A; /* length */ + out->sb[0] = buf[3]; /* checksum */ + i = 1; + break; + + case DRM_MODE_CONNECTOR_DisplayPort: + case DRM_MODE_CONNECTOR_eDP: + out->hb0 = 0x00; /* sdp id, zero */ + out->hb1 = 0x87; /* type */ + out->hb2 = 0x1D; /* payload len - 1 */ + out->hb3 = (0x13 << 2); /* sdp version */ + out->sb[0] = 0x01; /* version */ + out->sb[1] = 0x1A; /* length */ + i = 2; + break; + + default: + return -EINVAL; + } + + memcpy(&out->sb[i], &buf[4], 26); + out->valid = true; + + print_hex_dump(KERN_DEBUG, "HDR SB:", DUMP_PREFIX_NONE, 16, 1, out->sb, + sizeof(out->sb), false); + + return 0; +} +EXPORT_IF_KUNIT(amdgpu_dm_fill_hdr_info_packet); + +static int +amdgpu_dm_connector_atomic_check(struct drm_connector *conn, + struct drm_atomic_commit *state) +{ + struct drm_connector_state *new_con_state = + drm_atomic_get_new_connector_state(state, conn); + struct drm_connector_state *old_con_state = + drm_atomic_get_old_connector_state(state, conn); + struct drm_crtc *crtc = new_con_state->crtc; + struct drm_crtc_state *new_crtc_state; + struct amdgpu_dm_connector *aconn = to_amdgpu_dm_connector(conn); + int ret; + + if (WARN_ON(unlikely(!old_con_state || !new_con_state))) + return -EINVAL; + + trace_amdgpu_dm_connector_atomic_check(new_con_state); + + if (conn->connector_type == DRM_MODE_CONNECTOR_DisplayPort) { + ret = drm_dp_mst_root_conn_atomic_check(new_con_state, &aconn->mst_mgr); + if (ret < 0) + return ret; + } + + if (!crtc) + return 0; + + if (new_con_state->privacy_screen_sw_state != old_con_state->privacy_screen_sw_state) { + new_crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(new_crtc_state)) + return PTR_ERR(new_crtc_state); + + new_crtc_state->mode_changed = true; + } + + if (new_con_state->colorspace != old_con_state->colorspace) { + new_crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(new_crtc_state)) + return PTR_ERR(new_crtc_state); + + new_crtc_state->mode_changed = true; + } + + if (new_con_state->content_type != old_con_state->content_type) { + new_crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(new_crtc_state)) + return PTR_ERR(new_crtc_state); + + new_crtc_state->mode_changed = true; + } + + if (!drm_connector_atomic_hdr_metadata_equal(old_con_state, new_con_state)) { + struct dc_info_packet hdr_infopacket; + + ret = amdgpu_dm_fill_hdr_info_packet(new_con_state, &hdr_infopacket); + if (ret) + return ret; + + new_crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(new_crtc_state)) + return PTR_ERR(new_crtc_state); + + /* + * DC considers the stream backends changed if the + * static metadata changes. Forcing the modeset also + * gives a simple way for userspace to switch from + * 8bpc to 10bpc when setting the metadata to enter + * or exit HDR. + * + * Changing the static metadata after it's been + * set is permissible, however. So only force a + * modeset if we're entering or exiting HDR. + */ + new_crtc_state->mode_changed = new_crtc_state->mode_changed || + !old_con_state->hdr_output_metadata || + !new_con_state->hdr_output_metadata; + } + + return 0; +} + +static const struct drm_connector_helper_funcs +amdgpu_dm_connector_helper_funcs = { + /* + * If hotplugging a second bigger display in FB Con mode, bigger resolution + * modes will be filtered by drm_mode_validate_size(), and those modes + * are missing after user start lightdm. So we need to renew modes list. + * in get_modes call back, not just return the modes count + */ + .get_modes = get_modes, + .mode_valid = amdgpu_dm_connector_mode_valid, + .atomic_check = amdgpu_dm_connector_atomic_check, +}; + +int amdgpu_dm_convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth) +{ + switch (display_color_depth) { + case COLOR_DEPTH_666: + return 6; + case COLOR_DEPTH_888: + return 8; + case COLOR_DEPTH_101010: + return 10; + case COLOR_DEPTH_121212: + return 12; + case COLOR_DEPTH_141414: + return 14; + case COLOR_DEPTH_161616: + return 16; + default: + break; + } + return 0; +} +EXPORT_IF_KUNIT(amdgpu_dm_convert_dc_color_depth_into_bpc); + +STATIC_IFN_KUNIT int to_drm_connector_type(enum signal_type st, uint32_t connector_id) +{ + switch (st) { + case SIGNAL_TYPE_HDMI_TYPE_A: + return DRM_MODE_CONNECTOR_HDMIA; + case SIGNAL_TYPE_EDP: + return DRM_MODE_CONNECTOR_eDP; + case SIGNAL_TYPE_LVDS: + return DRM_MODE_CONNECTOR_LVDS; + case SIGNAL_TYPE_RGB: + return DRM_MODE_CONNECTOR_VGA; + case SIGNAL_TYPE_DISPLAY_PORT: + case SIGNAL_TYPE_DISPLAY_PORT_MST: + /* External DP bridges have a different connector type. */ + if (connector_id == CONNECTOR_ID_VGA) + return DRM_MODE_CONNECTOR_VGA; + else if (connector_id == CONNECTOR_ID_LVDS) + return DRM_MODE_CONNECTOR_LVDS; + + return DRM_MODE_CONNECTOR_DisplayPort; + case SIGNAL_TYPE_DVI_DUAL_LINK: + case SIGNAL_TYPE_DVI_SINGLE_LINK: + if (connector_id == CONNECTOR_ID_SINGLE_LINK_DVII || + connector_id == CONNECTOR_ID_DUAL_LINK_DVII) + return DRM_MODE_CONNECTOR_DVII; + + return DRM_MODE_CONNECTOR_DVID; + case SIGNAL_TYPE_VIRTUAL: + return DRM_MODE_CONNECTOR_VIRTUAL; + + default: + return DRM_MODE_CONNECTOR_Unknown; + } +} +EXPORT_IF_KUNIT(to_drm_connector_type); + +static struct drm_encoder *amdgpu_dm_connector_to_encoder(struct drm_connector *connector) +{ + struct drm_encoder *encoder; + + /* There is only one encoder per connector */ + drm_connector_for_each_possible_encoder(connector, encoder) + return encoder; + + return NULL; +} + +static void amdgpu_dm_get_native_mode(struct drm_connector *connector) +{ + struct drm_encoder *encoder; + struct amdgpu_encoder *amdgpu_encoder; + + encoder = amdgpu_dm_connector_to_encoder(connector); + + if (encoder == NULL) + return; + + amdgpu_encoder = to_amdgpu_encoder(encoder); + + amdgpu_encoder->native_mode.clock = 0; + + if (!list_empty(&connector->probed_modes)) { + struct drm_display_mode *preferred_mode = NULL; + + list_for_each_entry(preferred_mode, + &connector->probed_modes, + head) { + if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) + amdgpu_encoder->native_mode = *preferred_mode; + + break; + } + + } +} + +static struct drm_display_mode * +amdgpu_dm_create_common_mode(struct drm_encoder *encoder, + const char *name, + int hdisplay, int vdisplay) +{ + struct drm_device *dev = encoder->dev; + struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); + struct drm_display_mode *mode = NULL; + struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; + + mode = drm_mode_duplicate(dev, native_mode); + + if (mode == NULL) + return NULL; + + mode->hdisplay = hdisplay; + mode->vdisplay = vdisplay; + mode->type &= ~DRM_MODE_TYPE_PREFERRED; + strscpy(mode->name, name, DRM_DISPLAY_MODE_LEN); + + return mode; + +} + +static const struct amdgpu_dm_mode_size { + char name[DRM_DISPLAY_MODE_LEN]; + int w; + int h; +} common_modes[] = { + { "640x480", 640, 480}, + { "800x600", 800, 600}, + { "1024x768", 1024, 768}, + { "1280x720", 1280, 720}, + { "1280x800", 1280, 800}, + {"1280x1024", 1280, 1024}, + { "1440x900", 1440, 900}, + {"1680x1050", 1680, 1050}, + {"1600x1200", 1600, 1200}, + {"1920x1080", 1920, 1080}, + {"1920x1200", 1920, 1200} +}; + +static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); + struct drm_display_mode *mode = NULL; + struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode; + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + int i; + int n; + + if ((connector->connector_type != DRM_MODE_CONNECTOR_eDP) && + (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)) + return; + + n = ARRAY_SIZE(common_modes); + + for (i = 0; i < n; i++) { + struct drm_display_mode *curmode = NULL; + bool mode_existed = false; + + if (common_modes[i].w > native_mode->hdisplay || + common_modes[i].h > native_mode->vdisplay || + (common_modes[i].w == native_mode->hdisplay && + common_modes[i].h == native_mode->vdisplay)) + continue; + + list_for_each_entry(curmode, &connector->probed_modes, head) { + if (common_modes[i].w == curmode->hdisplay && + common_modes[i].h == curmode->vdisplay) { + mode_existed = true; + break; + } + } + + if (mode_existed) + continue; + + mode = amdgpu_dm_create_common_mode(encoder, + common_modes[i].name, common_modes[i].w, + common_modes[i].h); + if (!mode) + continue; + + drm_mode_probed_add(connector, mode); + amdgpu_dm_connector->num_modes++; + } +} + +void amdgpu_set_panel_orientation(struct drm_connector *connector) +{ + struct drm_encoder *encoder; + struct amdgpu_encoder *amdgpu_encoder; + const struct drm_display_mode *native_mode; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP && + connector->connector_type != DRM_MODE_CONNECTOR_LVDS) + return; + + mutex_lock(&connector->dev->mode_config.mutex); + amdgpu_dm_connector_get_modes(connector); + mutex_unlock(&connector->dev->mode_config.mutex); + + encoder = amdgpu_dm_connector_to_encoder(connector); + if (!encoder) + return; + + amdgpu_encoder = to_amdgpu_encoder(encoder); + + native_mode = &amdgpu_encoder->native_mode; + if (native_mode->hdisplay == 0 || native_mode->vdisplay == 0) + return; + + drm_connector_set_panel_orientation_with_quirk(connector, + DRM_MODE_PANEL_ORIENTATION_UNKNOWN, + native_mode->hdisplay, + native_mode->vdisplay); +} + +static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid) +{ + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + + if (drm_edid) { + /* empty probed_modes */ + INIT_LIST_HEAD(&connector->probed_modes); + amdgpu_dm_connector->num_modes = + drm_edid_connector_add_modes(connector); + + /* sorting the probed modes before calling function + * amdgpu_dm_get_native_mode() since EDID can have + * more than one preferred mode. The modes that are + * later in the probed mode list could be of higher + * and preferred resolution. For example, 3840x2160 + * resolution in base EDID preferred timing and 4096x2160 + * preferred resolution in DID extension block later. + */ + drm_mode_sort(&connector->probed_modes); + amdgpu_dm_get_native_mode(connector); + + /* Freesync capabilities are reset by calling + * drm_edid_connector_add_modes() and need to be + * restored here. + */ + amdgpu_dm_update_freesync_caps(connector, drm_edid, false); + } else { + amdgpu_dm_connector->num_modes = 0; + } +} + +STATIC_IFN_KUNIT bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector, + struct drm_display_mode *mode) +{ + struct drm_display_mode *m; + + list_for_each_entry(m, &aconnector->base.probed_modes, head) { + if (drm_mode_equal(m, mode)) + return true; + } + + return false; +} +EXPORT_IF_KUNIT(is_duplicate_mode); + +static uint add_fs_modes(struct amdgpu_dm_connector *aconnector) +{ + const struct drm_display_mode *m; + struct drm_display_mode *new_mode; + uint i; + u32 new_modes_count = 0; + + /* Standard FPS values + * + * 23.976 - TV/NTSC + * 24 - Cinema + * 25 - TV/PAL + * 29.97 - TV/NTSC + * 30 - TV/NTSC + * 48 - Cinema HFR + * 50 - TV/PAL + * 60 - Commonly used + * 48,72,96,120 - Multiples of 24 + */ + static const u32 common_rates[] = { + 23976, 24000, 25000, 29970, 30000, + 48000, 50000, 60000, 72000, 96000, 120000 + }; + + /* + * Find mode with highest refresh rate with the same resolution + * as the preferred mode. Some monitors report a preferred mode + * with lower resolution than the highest refresh rate supported. + */ + + m = amdgpu_dm_get_highest_refresh_rate_mode(aconnector, true); + if (!m) + return 0; + + for (i = 0; i < ARRAY_SIZE(common_rates); i++) { + u64 target_vtotal, target_vtotal_diff; + u64 num, den; + + if (drm_mode_vrefresh(m) * 1000 < common_rates[i]) + continue; + + if (common_rates[i] < aconnector->min_vfreq * 1000 || + common_rates[i] > aconnector->max_vfreq * 1000) + continue; + + num = (unsigned long long)m->clock * 1000 * 1000; + den = common_rates[i] * (unsigned long long)m->htotal; + target_vtotal = div_u64(num, den); + target_vtotal_diff = target_vtotal - m->vtotal; + + /* Check for illegal modes */ + if (m->vsync_start + target_vtotal_diff < m->vdisplay || + m->vsync_end + target_vtotal_diff < m->vsync_start || + m->vtotal + target_vtotal_diff < m->vsync_end) + continue; + + new_mode = drm_mode_duplicate(aconnector->base.dev, m); + if (!new_mode) + goto out; + + new_mode->vtotal += (u16)target_vtotal_diff; + new_mode->vsync_start += (u16)target_vtotal_diff; + new_mode->vsync_end += (u16)target_vtotal_diff; + new_mode->type &= ~DRM_MODE_TYPE_PREFERRED; + new_mode->type |= DRM_MODE_TYPE_DRIVER; + + if (!is_duplicate_mode(aconnector, new_mode)) { + drm_mode_probed_add(&aconnector->base, new_mode); + new_modes_count += 1; + } else + drm_mode_destroy(aconnector->base.dev, new_mode); + } + out: + return new_modes_count; +} + +static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connector, + const struct drm_edid *drm_edid) +{ + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + + if (!(amdgpu_freesync_vid_mode && drm_edid)) + return; + + if (!amdgpu_dm_connector->dc_sink || !amdgpu_dm_connector->dc_link) + return; + + if (!dc_supports_vrr(amdgpu_dm_connector->dc_sink->ctx->dce_version)) + return; + + if (dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id) && + amdgpu_dm_connector->dc_sink->edid_caps.analog) + return; + + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) + amdgpu_dm_connector->num_modes += + add_fs_modes(amdgpu_dm_connector); +} + +static int amdgpu_dm_connector_get_modes(struct drm_connector *connector) +{ + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + struct dc_link *dc_link = amdgpu_dm_connector->dc_link; + struct drm_encoder *encoder; + const struct drm_edid *drm_edid = amdgpu_dm_connector->drm_edid; + struct dc_link_settings *verified_link_cap = &dc_link->verified_link_cap; + const struct dc *dc = dc_link->dc; + + encoder = amdgpu_dm_connector_to_encoder(connector); + + if (!drm_edid) { + amdgpu_dm_connector->num_modes = + drm_add_modes_noedid(connector, 640, 480); + if (dc->link_srv->dp_get_encoding_format(verified_link_cap) == DP_128b_132b_ENCODING) + amdgpu_dm_connector->num_modes += + drm_add_modes_noedid(connector, 1920, 1080); + + if (amdgpu_dm_connector->dc_sink && + amdgpu_dm_connector->dc_sink->edid_caps.analog && + dc_connector_supports_analog(dc_link->link_id.id)) { + /* Analog monitor connected by DAC load detection. + * Add common modes. It will be up to the user to select one that works. + */ + for (int i = 0; i < ARRAY_SIZE(common_modes); i++) + amdgpu_dm_connector->num_modes += drm_add_modes_noedid( + connector, common_modes[i].w, common_modes[i].h); + } + } else { + amdgpu_dm_connector_ddc_get_modes(connector, drm_edid); + if (encoder) + amdgpu_dm_connector_add_common_modes(encoder, connector); + amdgpu_dm_connector_add_freesync_modes(connector, drm_edid); + } + amdgpu_dm_fbc_init(connector); + + return amdgpu_dm_connector->num_modes; +} + +static const u32 supported_colorspaces = + BIT(DRM_MODE_COLORIMETRY_BT709_YCC) | + BIT(DRM_MODE_COLORIMETRY_OPRGB) | + BIT(DRM_MODE_COLORIMETRY_BT2020_RGB) | + BIT(DRM_MODE_COLORIMETRY_BT2020_YCC); + +static const u32 supported_colorformats = + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420); + +static void hdmi_frl_status_polling_work(struct work_struct *work) +{ + struct amdgpu_display_manager *dm = + container_of(to_delayed_work(work), struct amdgpu_display_manager, + hdmi_frl_status_polling_work); + struct dc *dc = dm->dc; + struct dc_link *dc_link; + bool link_update = false; + + for (int i = 0; i < MAX_LINKS; i++) { + dc_link = dc->links[i]; + + + if (!dc_link || !dc_link->local_sink) + continue; + + if (!dc_is_hdmi_signal(dc_link->connector_signal)) + continue; + + if (dc_link->connector_signal != SIGNAL_TYPE_HDMI_FRL) + continue; + + link_update = dc_link_frl_poll_status_flag(dc_link); + if (link_update) { + mutex_lock(&dm->dc_lock); + dc_link_detect(dc_link, DETECT_REASON_RETRAIN); + mutex_unlock(&dm->dc_lock); + } + } + + queue_delayed_work(dm->hdmi_frl_status_polling_wq, + &dm->hdmi_frl_status_polling_work, + msecs_to_jiffies(dm->hdmi_frl_status_polling_delay_ms)); +} + +void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, + struct amdgpu_dm_connector *aconnector, + int connector_type, + struct dc_link *link, + int link_index) +{ + struct amdgpu_device *adev = drm_to_adev(dm->ddev); + + /* + * Some of the properties below require access to state, like bpc. + * Allocate some default initial connector state with our reset helper. + */ + if (aconnector->base.funcs->reset) + aconnector->base.funcs->reset(&aconnector->base); + + aconnector->connector_id = link_index; + aconnector->bl_idx = -1; + aconnector->dc_link = link; + aconnector->base.interlace_allowed = false; + aconnector->base.doublescan_allowed = false; + aconnector->base.stereo_allowed = false; + aconnector->base.dpms = DRM_MODE_DPMS_OFF; + aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */ + aconnector->audio_inst = -1; + aconnector->pack_sdp_v1_3 = false; + aconnector->as_type = ADAPTIVE_SYNC_TYPE_NONE; + memset(&aconnector->vsdb_info, 0, sizeof(aconnector->vsdb_info)); + mutex_init(&aconnector->hpd_lock); + mutex_init(&aconnector->handle_mst_msg_ready); + + /* + * If HDMI HPD debounce delay is set, use the minimum between selected + * value and AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS + */ + if (amdgpu_hdmi_hpd_debounce_delay_ms) { + aconnector->hdmi_hpd_debounce_delay_ms = min(amdgpu_hdmi_hpd_debounce_delay_ms, + AMDGPU_DM_MAX_HDMI_HPD_DEBOUNCE_MS); + INIT_DELAYED_WORK(&aconnector->hdmi_hpd_debounce_work, amdgpu_dm_hdmi_hpd_debounce_work); + aconnector->hdmi_prev_sink = NULL; + } else { + aconnector->hdmi_hpd_debounce_delay_ms = 0; + } + + dm->hdmi_frl_status_polling_delay_ms = 200; + INIT_DELAYED_WORK(&dm->hdmi_frl_status_polling_work, hdmi_frl_status_polling_work); + /* + * configure support HPD hot plug connector_>polled default value is 0 + * which means HPD hot plug not supported + */ + switch (connector_type) { + case DRM_MODE_CONNECTOR_HDMIA: + aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; + aconnector->base.ycbcr_420_allowed = + link->link_enc->features.hdmi_ycbcr420_supported ? true : false; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; + link->link_enc = link_enc_cfg_get_link_enc(link); + ASSERT(link->link_enc); + if (link->link_enc) + aconnector->base.ycbcr_420_allowed = + link->link_enc->features.dp_ycbcr420_supported ? true : false; + break; + case DRM_MODE_CONNECTOR_DVID: + aconnector->base.polled = DRM_CONNECTOR_POLL_HPD; + break; + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_VGA: + aconnector->base.polled = + DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + break; + default: + break; + } + + drm_object_attach_property(&aconnector->base.base, + dm->ddev->mode_config.scaling_mode_property, + DRM_MODE_SCALE_NONE); + + if (connector_type == DRM_MODE_CONNECTOR_HDMIA + || (connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root)) + drm_connector_attach_broadcast_rgb_property(&aconnector->base); + + drm_object_attach_property(&aconnector->base.base, + adev->mode_info.underscan_property, + UNDERSCAN_OFF); + drm_object_attach_property(&aconnector->base.base, + adev->mode_info.underscan_hborder_property, + 0); + drm_object_attach_property(&aconnector->base.base, + adev->mode_info.underscan_vborder_property, + 0); + + if (!aconnector->mst_root) + drm_connector_attach_max_bpc_property(&aconnector->base, 8, 16); + + aconnector->base.state->max_bpc = 16; + aconnector->base.state->max_requested_bpc = aconnector->base.state->max_bpc; + + if (connector_type == DRM_MODE_CONNECTOR_HDMIA) { + /* Content Type is currently only implemented for HDMI. */ + drm_connector_attach_content_type_property(&aconnector->base); + } + + if (connector_type == DRM_MODE_CONNECTOR_HDMIA) { + if (!drm_mode_create_hdmi_colorspace_property(&aconnector->base, supported_colorspaces)) + drm_connector_attach_colorspace_property(&aconnector->base); + } else if ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !aconnector->mst_root) || + connector_type == DRM_MODE_CONNECTOR_eDP) { + if (!drm_mode_create_dp_colorspace_property(&aconnector->base, supported_colorspaces)) + drm_connector_attach_colorspace_property(&aconnector->base); + } + + if (connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector_type == DRM_MODE_CONNECTOR_eDP) { + drm_connector_attach_hdr_output_metadata_property(&aconnector->base); + + if (!aconnector->mst_root) { + drm_connector_attach_vrr_capable_property(&aconnector->base); + drm_connector_attach_color_format_property(&aconnector->base, + supported_colorformats); + } + + + if (adev->dm.hdcp_workqueue) + drm_connector_attach_content_protection_property(&aconnector->base, true); + } + + if (connector_type == DRM_MODE_CONNECTOR_eDP) { + struct drm_privacy_screen *privacy_screen; + + drm_connector_attach_panel_type_property(&aconnector->base); + + privacy_screen = drm_privacy_screen_get(adev_to_drm(adev)->dev, NULL); + if (!IS_ERR(privacy_screen)) { + drm_connector_attach_privacy_screen_provider(&aconnector->base, + privacy_screen); + } else if (PTR_ERR(privacy_screen) != -ENODEV) { + drm_warn(adev_to_drm(adev), "Error getting privacy-screen\n"); + } + } +} + +static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + struct amdgpu_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap); + struct ddc_service *ddc_service = i2c->ddc_service; + struct i2c_command cmd; + int i; + int result = -EIO; + + if (!ddc_service->ddc_pin) + return result; + + cmd.payloads = kzalloc_objs(struct i2c_payload, num); + + if (!cmd.payloads) + return result; + + cmd.number_of_payloads = num; + cmd.engine = I2C_COMMAND_ENGINE_DEFAULT; + cmd.speed = 100; + + for (i = 0; i < num; i++) { + cmd.payloads[i].write = !(msgs[i].flags & I2C_M_RD); + cmd.payloads[i].address = msgs[i].addr; + cmd.payloads[i].length = msgs[i].len; + cmd.payloads[i].data = msgs[i].buf; + } + + if (i2c->oem) { + if (dc_submit_i2c_oem( + ddc_service->ctx->dc, + &cmd)) + result = num; + } else { + if (dc_submit_i2c( + ddc_service->ctx->dc, + ddc_service->link->link_index, + &cmd)) + result = num; + } + + kfree(cmd.payloads); + return result; +} + +static u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm amdgpu_dm_i2c_algo = { + .master_xfer = amdgpu_dm_i2c_xfer, + .functionality = amdgpu_dm_i2c_func, +}; + +struct amdgpu_i2c_adapter * +amdgpu_dm_create_i2c(struct ddc_service *ddc_service, bool oem) +{ + struct amdgpu_device *adev = ddc_service->ctx->driver_context; + struct amdgpu_i2c_adapter *i2c; + + i2c = kzalloc_obj(struct amdgpu_i2c_adapter); + if (!i2c) + return NULL; + i2c->base.owner = THIS_MODULE; + i2c->base.dev.parent = &adev->pdev->dev; + i2c->base.algo = &amdgpu_dm_i2c_algo; + if (oem) + snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c OEM bus"); + else + snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d", + ddc_service->link->link_index); + i2c_set_adapdata(&i2c->base, i2c); + i2c->ddc_service = ddc_service; + i2c->oem = oem; + + return i2c; +} + +int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector) +{ + struct cec_connector_info conn_info; + struct drm_device *ddev = aconnector->base.dev; + struct device *hdmi_dev = ddev->dev; + + if (amdgpu_dc_debug_mask & DC_DISABLE_HDMI_CEC) { + drm_info(ddev, "HDMI-CEC feature masked\n"); + return -EINVAL; + } + + cec_fill_conn_info_from_drm(&conn_info, &aconnector->base); + aconnector->notifier = + cec_notifier_conn_register(hdmi_dev, NULL, &conn_info); + if (!aconnector->notifier) { + drm_err(ddev, "Failed to create cec notifier\n"); + return -ENOMEM; + } + + return 0; +} + +/* + * Note: this function assumes that dc_link_detect() was called for the + * dc_link which will be represented by this aconnector. + */ +int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, + struct amdgpu_dm_connector *aconnector, + u32 link_index, + struct amdgpu_encoder *aencoder) +{ + int res = 0; + int connector_type; + struct dc *dc = dm->dc; + struct dc_link *link = dc_get_link_at_index(dc, link_index); + struct amdgpu_i2c_adapter *i2c; + + /* Not needed for writeback connector */ + link->priv = aconnector; + + + i2c = amdgpu_dm_create_i2c(link->ddc, false); + if (!i2c) { + drm_err(adev_to_drm(dm->adev), "Failed to create i2c adapter data\n"); + return -ENOMEM; + } + + aconnector->i2c = i2c; + res = devm_i2c_add_adapter(dm->adev->dev, &i2c->base); + + if (res) { + drm_err(adev_to_drm(dm->adev), "Failed to register hw i2c %d\n", link->link_index); + goto out_free; + } + + connector_type = to_drm_connector_type(link->connector_signal, link->link_id.id); + + res = drm_connector_init_with_ddc( + dm->ddev, + &aconnector->base, + &amdgpu_dm_connector_funcs, + connector_type, + &i2c->base); + + if (res) { + drm_err(adev_to_drm(dm->adev), "connector_init failed\n"); + aconnector->connector_id = -1; + goto out_free; + } + + drm_connector_helper_add( + &aconnector->base, + &amdgpu_dm_connector_helper_funcs); + + amdgpu_dm_connector_init_helper( + dm, + aconnector, + connector_type, + link, + link_index); + + drm_connector_attach_encoder( + &aconnector->base, &aencoder->base); + + if (connector_type == DRM_MODE_CONNECTOR_HDMIA || + connector_type == DRM_MODE_CONNECTOR_HDMIB) + amdgpu_dm_initialize_hdmi_connector(aconnector); + + if (dc_is_dp_signal(link->connector_signal)) + amdgpu_dm_initialize_dp_connector(dm, aconnector, link->link_index); + +out_free: + if (res) { + kfree(i2c); + aconnector->i2c = NULL; + } + return res; +} + +static int dm_force_atomic_commit(struct drm_connector *connector) +{ + int ret = 0; + struct drm_device *ddev = connector->dev; + struct drm_atomic_commit *state = drm_atomic_commit_alloc(ddev); + struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc); + struct drm_plane *plane = disconnected_acrtc->base.primary; + struct drm_connector_state *conn_state; + struct drm_crtc_state *crtc_state; + struct drm_plane_state *plane_state; + + if (!state) + return -ENOMEM; + + state->acquire_ctx = ddev->mode_config.acquire_ctx; + + /* Construct an atomic state to restore previous display setting */ + + /* + * Attach connectors to drm_atomic_commit + */ + conn_state = drm_atomic_get_connector_state(state, connector); + + /* Check for error in getting connector state */ + if (IS_ERR(conn_state)) { + ret = PTR_ERR(conn_state); + goto out; + } + + /* Attach crtc to drm_atomic_commit*/ + crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base); + + /* Check for error in getting crtc state */ + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto out; + } + + /* force a restore */ + crtc_state->mode_changed = true; + + /* Attach plane to drm_atomic_commit */ + plane_state = drm_atomic_get_plane_state(state, plane); + + /* Check for error in getting plane state */ + if (IS_ERR(plane_state)) { + ret = PTR_ERR(plane_state); + goto out; + } + + /* Call commit internally with the state we just constructed */ + ret = drm_atomic_commit(state); + +out: + drm_atomic_commit_put(state); + if (ret) + drm_err(ddev, "Restoring old state failed with %i\n", ret); + + return ret; +} + +/* + * This function handles all cases when set mode does not come upon hotplug. + * This includes when a display is unplugged then plugged back into the + * same port and when running without usermode desktop manager support + */ +void dm_restore_drm_connector_state(struct drm_device *dev, + struct drm_connector *connector) +{ + struct amdgpu_dm_connector *aconnector; + struct amdgpu_crtc *disconnected_acrtc; + struct dm_crtc_state *acrtc_state; + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + return; + + aconnector = to_amdgpu_dm_connector(connector); + + if (!aconnector->dc_sink || !connector->state || !connector->encoder) + return; + + disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc); + if (!disconnected_acrtc) + return; + + acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state); + if (!acrtc_state->stream) + return; + + /* + * If the previous sink is not released and different from the current, + * we deduce we are in a state where we can not rely on usermode call + * to turn on the display, so we do it here + */ + if (acrtc_state->stream->sink != aconnector->dc_sink) + dm_force_atomic_commit(&aconnector->base); +} + +static bool dm_edid_parser_send_cea(struct amdgpu_display_manager *dm, + unsigned int offset, + unsigned int total_length, + u8 *data, + unsigned int length, + struct amdgpu_hdmi_vsdb_info *vsdb) +{ + bool res; + union dmub_rb_cmd cmd; + struct dmub_cmd_send_edid_cea *input; + struct dmub_cmd_edid_cea_output *output; + + if (length > DMUB_EDID_CEA_DATA_CHUNK_BYTES) + return false; + + memset(&cmd, 0, sizeof(cmd)); + + input = &cmd.edid_cea.data.input; + + cmd.edid_cea.header.type = DMUB_CMD__EDID_CEA; + cmd.edid_cea.header.sub_type = 0; + cmd.edid_cea.header.payload_bytes = + sizeof(cmd.edid_cea) - sizeof(cmd.edid_cea.header); + input->offset = offset; + input->length = length; + input->cea_total_length = total_length; + memcpy(input->payload, data, length); + + res = dc_wake_and_execute_dmub_cmd(dm->dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY); + if (!res) { + drm_err(adev_to_drm(dm->adev), "EDID CEA parser failed\n"); + return false; + } + + output = &cmd.edid_cea.data.output; + + if (output->type == DMUB_CMD__EDID_CEA_ACK) { + if (!output->ack.success) { + drm_err(adev_to_drm(dm->adev), "EDID CEA ack failed at offset %d\n", + output->ack.offset); + } + } else if (output->type == DMUB_CMD__EDID_CEA_AMD_VSDB) { + if (!output->amd_vsdb.vsdb_found) + return false; + + vsdb->freesync_supported = output->amd_vsdb.freesync_supported; + vsdb->amd_vsdb_version = output->amd_vsdb.amd_vsdb_version; + vsdb->min_refresh_rate_hz = output->amd_vsdb.min_frame_rate; + vsdb->max_refresh_rate_hz = output->amd_vsdb.max_frame_rate; + vsdb->freesync_mccs_vcp_code = output->amd_vsdb.freesync_mccs_vcp_code; + } else { + drm_warn(adev_to_drm(dm->adev), "Unknown EDID CEA parser results\n"); + return false; + } + + return true; +} + +static bool parse_edid_cea_dmcu(struct amdgpu_display_manager *dm, + u8 *edid_ext, int len, + struct amdgpu_hdmi_vsdb_info *vsdb_info) +{ + int i; + + /* send extension block to DMCU for parsing */ + for (i = 0; i < len; i += 8) { + bool res; + int offset; + + /* send 8 bytes a time */ + if (!dc_edid_parser_send_cea(dm->dc, i, len, &edid_ext[i], 8)) + return false; + + if (i+8 == len) { + /* EDID block sent completed, expect result */ + int version, min_rate, max_rate; + + res = dc_edid_parser_recv_amd_vsdb(dm->dc, &version, &min_rate, &max_rate); + if (res) { + /* amd vsdb found */ + vsdb_info->freesync_supported = 1; + vsdb_info->amd_vsdb_version = version; + vsdb_info->min_refresh_rate_hz = min_rate; + vsdb_info->max_refresh_rate_hz = max_rate; + /* Not enabled on DMCU*/ + vsdb_info->freesync_mccs_vcp_code = 0; + return true; + } + /* not amd vsdb */ + return false; + } + + /* check for ack*/ + res = dc_edid_parser_recv_cea_ack(dm->dc, &offset); + if (!res) + return false; + } + + return false; +} + +static bool parse_edid_cea_dmub(struct amdgpu_display_manager *dm, + u8 *edid_ext, int len, + struct amdgpu_hdmi_vsdb_info *vsdb_info) +{ + int i; + + /* send extension block to DMCU for parsing */ + for (i = 0; i < len; i += 8) { + /* send 8 bytes a time */ + if (!dm_edid_parser_send_cea(dm, i, len, &edid_ext[i], 8, vsdb_info)) + return false; + } + + return vsdb_info->freesync_supported; +} + +static bool parse_edid_cea(struct amdgpu_dm_connector *aconnector, + u8 *edid_ext, int len, + struct amdgpu_hdmi_vsdb_info *vsdb_info) +{ + struct amdgpu_device *adev = drm_to_adev(aconnector->base.dev); + bool ret; + + mutex_lock(&adev->dm.dc_lock); + if (adev->dm.dmub_srv) + ret = parse_edid_cea_dmub(&adev->dm, edid_ext, len, vsdb_info); + else + ret = parse_edid_cea_dmcu(&adev->dm, edid_ext, len, vsdb_info); + mutex_unlock(&adev->dm.dc_lock); + return ret; +} + +static void parse_edid_displayid_vrr(struct drm_connector *connector, + const struct edid *edid) +{ + u8 *edid_ext = NULL; + int i; + int j = 0; + u16 min_vfreq; + u16 max_vfreq; + + if (!edid || !edid->extensions) + return; + + /* Find DisplayID extension */ + for (i = 0; i < edid->extensions; i++) { + edid_ext = (void *)(edid + (i + 1)); + if (edid_ext[0] == DISPLAYID_EXT) + break; + } + + if (i == edid->extensions) + return; + + while (j < EDID_LENGTH) { + /* Get dynamic video timing range from DisplayID if available */ + if (EDID_LENGTH - j > 13 && edid_ext[j] == 0x25 && + (edid_ext[j+1] & 0xFE) == 0 && (edid_ext[j+2] == 9)) { + min_vfreq = edid_ext[j+9]; + if (edid_ext[j+1] & 7) + max_vfreq = edid_ext[j+10] + ((edid_ext[j+11] & 3) << 8); + else + max_vfreq = edid_ext[j+10]; + + if (max_vfreq && min_vfreq) { + connector->display_info.monitor_range.max_vfreq = max_vfreq; + connector->display_info.monitor_range.min_vfreq = min_vfreq; + + return; + } + } + j++; + } +} + +static int get_amd_vsdb(struct amdgpu_dm_connector *aconnector, + struct amdgpu_hdmi_vsdb_info *vsdb_info) +{ + struct drm_connector *connector = &aconnector->base; + + vsdb_info->replay_mode = connector->display_info.amd_vsdb.replay_mode; + vsdb_info->amd_vsdb_version = connector->display_info.amd_vsdb.version; + + return connector->display_info.amd_vsdb.version != 0; +} + +static int parse_hdmi_amd_vsdb(struct amdgpu_dm_connector *aconnector, + const struct edid *edid, + struct amdgpu_hdmi_vsdb_info *vsdb_info) +{ + u8 *edid_ext = NULL; + int i; + bool valid_vsdb_found = false; + + /*----- drm_find_cea_extension() -----*/ + /* No EDID or EDID extensions */ + if (edid == NULL || edid->extensions == 0) + return -ENODEV; + + /* Find CEA extension */ + for (i = 0; i < edid->extensions; i++) { + edid_ext = (uint8_t *)edid + EDID_LENGTH * (i + 1); + if (edid_ext[0] == CEA_EXT) + break; + } + + if (i == edid->extensions) + return -ENODEV; + + /*----- cea_db_offsets() -----*/ + if (edid_ext[0] != CEA_EXT) + return -ENODEV; + + valid_vsdb_found = parse_edid_cea(aconnector, edid_ext, EDID_LENGTH, vsdb_info); + + return valid_vsdb_found ? i : -ENODEV; +} + +/** + * amdgpu_dm_update_freesync_caps - Update Freesync capabilities + * + * @connector: Connector to query. + * @drm_edid: DRM EDID from monitor + * @do_mccs: Controls whether MCCS (Monitor Control Command Set) over + * DDC (Display Data Channel) transactions are performed. When true, + * the driver queries the monitor to get or update additional FreeSync + * capability information. When false, these transactions are skipped. + * + * Amdgpu supports Freesync in DP and HDMI displays, and it is required to keep + * track of some of the display information in the internal data struct used by + * amdgpu_dm. This function checks which type of connector we need to set the + * FreeSync parameters. + */ +void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, + const struct drm_edid *drm_edid, bool do_mccs) +{ + int i = 0; + struct amdgpu_dm_connector *amdgpu_dm_connector = + to_amdgpu_dm_connector(connector); + struct dm_connector_state *dm_con_state = NULL; + struct dc_sink *sink; + struct amdgpu_device *adev = drm_to_adev(connector->dev); + struct amdgpu_hdmi_vsdb_info vsdb_info = {0}; + const struct edid *edid; + bool freesync_capable = false; + enum adaptive_sync_type as_type = ADAPTIVE_SYNC_TYPE_NONE; + + if (!connector->state) { + drm_err(adev_to_drm(adev), "%s - Connector has no state", __func__); + goto update; + } + + sink = amdgpu_dm_connector->dc_sink ? + amdgpu_dm_connector->dc_sink : + amdgpu_dm_connector->dc_em_sink; + + drm_edid_connector_update(connector, drm_edid); + + if (!drm_edid || !sink) { + dm_con_state = to_dm_connector_state(connector->state); + + amdgpu_dm_connector->min_vfreq = 0; + amdgpu_dm_connector->max_vfreq = 0; + freesync_capable = false; + + goto update; + } + + dm_con_state = to_dm_connector_state(connector->state); + + if (!adev->dm.freesync_module || !dc_supports_vrr(sink->ctx->dce_version)) + goto update; + + /* FIXME: Get rid of drm_edid_raw() */ + edid = drm_edid_raw(drm_edid); + + /* Some eDP panels only have the refresh rate range info in DisplayID */ + if ((connector->display_info.monitor_range.min_vfreq == 0 || + connector->display_info.monitor_range.max_vfreq == 0)) + parse_edid_displayid_vrr(connector, edid); + + if (edid && (sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT || + sink->sink_signal == SIGNAL_TYPE_EDP)) { + if (amdgpu_dm_connector->dc_link && + amdgpu_dm_connector->dc_link->dpcd_caps.allow_invalid_MSA_timing_param) { + amdgpu_dm_connector->min_vfreq = connector->display_info.monitor_range.min_vfreq; + amdgpu_dm_connector->max_vfreq = connector->display_info.monitor_range.max_vfreq; + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) + freesync_capable = true; + } + + get_amd_vsdb(amdgpu_dm_connector, &vsdb_info); + + if (vsdb_info.replay_mode) { + amdgpu_dm_connector->vsdb_info.replay_mode = vsdb_info.replay_mode; + amdgpu_dm_connector->vsdb_info.amd_vsdb_version = vsdb_info.amd_vsdb_version; + amdgpu_dm_connector->as_type = ADAPTIVE_SYNC_TYPE_EDP; + } + + } else if (drm_edid && sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A) { + i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); + if (i >= 0) { + amdgpu_dm_connector->vsdb_info = vsdb_info; + sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code; + + if (vsdb_info.freesync_supported) { + amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; + amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) + freesync_capable = true; + + connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; + connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; + } + } + } + + if (amdgpu_dm_connector->dc_link) + as_type = dm_get_adaptive_sync_support_type(amdgpu_dm_connector->dc_link); + + if (as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) { + i = parse_hdmi_amd_vsdb(amdgpu_dm_connector, edid, &vsdb_info); + if (i >= 0) { + amdgpu_dm_connector->vsdb_info = vsdb_info; + sink->edid_caps.freesync_vcp_code = vsdb_info.freesync_mccs_vcp_code; + + if (vsdb_info.freesync_supported && vsdb_info.amd_vsdb_version > 0) { + amdgpu_dm_connector->pack_sdp_v1_3 = true; + amdgpu_dm_connector->as_type = as_type; + + amdgpu_dm_connector->min_vfreq = vsdb_info.min_refresh_rate_hz; + amdgpu_dm_connector->max_vfreq = vsdb_info.max_refresh_rate_hz; + if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10) + freesync_capable = true; + + connector->display_info.monitor_range.min_vfreq = vsdb_info.min_refresh_rate_hz; + connector->display_info.monitor_range.max_vfreq = vsdb_info.max_refresh_rate_hz; + } + } + } + + /* Handle MCCS */ + if (do_mccs) + dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + + if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || + as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) && + (!sink->edid_caps.freesync_vcp_code || + (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported))) + freesync_capable = false; + + if (do_mccs && sink->mccs_caps.freesync_supported && freesync_capable) + dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + +update: + if (dm_con_state) + dm_con_state->freesync_capable = freesync_capable; + + if (connector->state && amdgpu_dm_connector->dc_link && !freesync_capable && + amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported) { + amdgpu_dm_connector->dc_link->replay_settings.config.replay_supported = false; + amdgpu_dm_connector->dc_link->replay_settings.replay_feature_enabled = false; + } + + if (connector->vrr_capable_property) + drm_connector_set_vrr_capable_property(connector, + freesync_capable); +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h new file mode 100644 index 000000000000..c5b8b13f8f06 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __AMDGPU_DM_CONNECTOR_H__ +#define __AMDGPU_DM_CONNECTOR_H__ + +struct amdgpu_device; +struct amdgpu_dm_connector; +struct amdgpu_display_manager; +struct amdgpu_encoder; +struct amdgpu_i2c_adapter; +struct dc_crtc_timing; +struct dc_link; +enum signal_type; +struct dc_state; +struct dc_stream_state; +struct ddc_service; +struct dm_connector_state; +struct drm_atomic_commit; +struct drm_device; +struct drm_encoder_helper_funcs; +struct drm_connector; +struct drm_connector_state; +struct drm_crtc; +struct drm_device; +struct drm_display_mode; +struct drm_edid; +struct drm_property; + +void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector); + +struct drm_connector_state * +amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector); + +int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector, + struct drm_connector_state *connector_state, + struct drm_property *property, + uint64_t val); + +int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector, + const struct drm_connector_state *state, + struct drm_property *property, + uint64_t *val); + +void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, + struct amdgpu_dm_connector *aconnector, + int connector_type, + struct dc_link *link, + int link_index); + +enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connector, + const struct drm_display_mode *mode); + +void dm_restore_drm_connector_state(struct drm_device *dev, + struct drm_connector *connector); + +void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, + const struct drm_edid *drm_edid, + bool do_mccs); + +void amdgpu_dm_update_connector_after_detect( + struct amdgpu_dm_connector *aconnector); + +void amdgpu_dm_hdmi_cec_set_edid(struct amdgpu_dm_connector *aconnector); +int amdgpu_dm_initialize_hdmi_connector(struct amdgpu_dm_connector *aconnector); + +struct drm_connector * +amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_commit *state, + struct drm_crtc *crtc); + +int amdgpu_dm_convert_dc_color_depth_into_bpc(enum dc_color_depth display_color_depth); + +struct dc_stream_state * +amdgpu_dm_create_validate_stream_for_sink(struct drm_connector *connector, + const struct drm_display_mode *drm_mode, + const struct dm_connector_state *dm_state, + const struct dc_stream_state *old_stream); + +int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm, + struct amdgpu_dm_connector *amdgpu_dm_connector, + u32 link_index, + struct amdgpu_encoder *amdgpu_encoder); + +void amdgpu_dm_s3_handle_hdmi_cec(struct drm_device *ddev, bool suspend); + +int amdgpu_dm_detect_mst_link_for_all_connectors(struct drm_device *dev); + +void amdgpu_set_panel_orientation(struct drm_connector *connector); + +enum dc_color_depth +amdgpu_dm_convert_color_depth_from_display_info(const struct drm_connector *connector, + bool is_y420, int requested_bpc); + +void amdgpu_dm_update_stream_scaling_settings(struct drm_device *dev, + const struct drm_display_mode *mode, + const struct dm_connector_state *dm_state, + struct dc_stream_state *stream); + +bool amdgpu_dm_is_freesync_video_mode(const struct drm_display_mode *mode, + struct amdgpu_dm_connector *aconnector); + +int amdgpu_dm_fill_hdr_info_packet(const struct drm_connector_state *state, + struct dc_info_packet *out); + +enum dc_color_space +amdgpu_dm_get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, + const struct drm_connector_state *connector_state); + +struct drm_display_mode * +amdgpu_dm_get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector, + bool use_probed_modes); + +struct amdgpu_i2c_adapter * +amdgpu_dm_create_i2c(struct ddc_service *ddc_service, bool oem); + +#define DDC_MANUFACTURERNAME_SAMSUNG 0x2D4C + +/* Encoder functions */ +extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs; +int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev); +int amdgpu_dm_encoder_init(struct drm_device *dev, + struct amdgpu_encoder *aencoder, + uint32_t link_index); + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +enum drm_mode_subconnector get_subconnector_type(struct dc_link *link); +enum display_content_type +get_output_content_type(const struct drm_connector_state *connector_state); +bool adjust_colour_depth_from_display_info(struct dc_crtc_timing *timing_out, + const struct drm_display_info *info); + +int to_drm_connector_type(enum signal_type st, uint32_t connector_id); +bool is_duplicate_mode(struct amdgpu_dm_connector *aconnector, struct drm_display_mode *mode); +enum dc_aspect_ratio get_aspect_ratio(const struct drm_display_mode *mode_in); +void decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode, + const struct drm_display_mode *native_mode, + bool scale_enabled); +#endif +#endif /* __AMDGPU_DM_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c index 88f7cfea5624..970490c401e9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c @@ -87,6 +87,65 @@ bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src) } EXPORT_IF_KUNIT(dm_need_crc_dither); +/** + * dm_need_dp_aux() - Does this source transition require the DP AUX handle? + * @source: Requested CRC source. + * @cur_crc_src: Current CRC source. + * + * Returns true when either the new source is DPRX-based (starting DPRX CRC), + * or the current source is DPRX-based and the new source is NONE (stopping it). + * + * Return: true if the DP AUX handle is needed, false otherwise. + */ +STATIC_IFN_KUNIT +bool dm_need_dp_aux(enum amdgpu_dm_pipe_crc_source source, + enum amdgpu_dm_pipe_crc_source cur_crc_src) +{ + return dm_is_crc_source_dprx(source) || + (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE && dm_is_crc_source_dprx(cur_crc_src)); +} +EXPORT_IF_KUNIT(dm_need_dp_aux); + +/** + * dm_crc_source_should_start_dprx() - Should drm_dp_start_crc() be called? + * @source: Requested CRC source. + * @cur_crc_src: Current CRC source. + * + * True when CRC is transitioning from off to a DPRX source + * (!enabled && enable && is_dprx(@source)). + * + * Return: true if drm_dp_start_crc() should be called, false otherwise. + */ +STATIC_IFN_KUNIT +bool dm_crc_source_should_start_dprx(enum amdgpu_dm_pipe_crc_source source, + enum amdgpu_dm_pipe_crc_source cur_crc_src) +{ + return !amdgpu_dm_is_valid_crc_source(cur_crc_src) && + amdgpu_dm_is_valid_crc_source(source) && + dm_is_crc_source_dprx(source); +} +EXPORT_IF_KUNIT(dm_crc_source_should_start_dprx); + +/** + * dm_crc_source_should_stop_dprx() - Should drm_dp_stop_crc() be called? + * @source: Requested CRC source. + * @cur_crc_src: Current CRC source. + * + * True when CRC is transitioning from a DPRX source to off + * (enabled && !enable && is_dprx(@cur_crc_src)). + * + * Return: true if drm_dp_stop_crc() should be called, false otherwise. + */ +STATIC_IFN_KUNIT +bool dm_crc_source_should_stop_dprx(enum amdgpu_dm_pipe_crc_source source, + enum amdgpu_dm_pipe_crc_source cur_crc_src) +{ + return amdgpu_dm_is_valid_crc_source(cur_crc_src) && + !amdgpu_dm_is_valid_crc_source(source) && + dm_is_crc_source_dprx(cur_crc_src); +} +EXPORT_IF_KUNIT(dm_crc_source_should_stop_dprx); + const char *const *amdgpu_dm_crtc_get_crc_sources(struct drm_crtc *crtc, size_t *count) { @@ -496,7 +555,7 @@ amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name, { enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name); - if (source < 0) { + if (source == AMDGPU_DM_PIPE_CRC_SOURCE_INVALID) { DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n", src_name, crtc->index); return -EINVAL; @@ -595,7 +654,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) bool enabled = false; int ret = 0; - if (source < 0) { + if (source == AMDGPU_DM_PIPE_CRC_SOURCE_INVALID) { DRM_DEBUG_DRIVER("Unknown CRC source %s for CRTC%d\n", src_name, crtc->index); return -EINVAL; @@ -622,7 +681,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) */ ret = wait_for_completion_interruptible_timeout( &commit->hw_done, 10 * HZ); - if (ret < 0) + if (ret < 0 && ret != -ERESTARTSYS) goto cleanup; if (ret == 0) { @@ -650,9 +709,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) * CRTC DITHER | XXXX | Enable CRTC CRC, set dither * DPRX DITHER | XXXX | Enable DPRX CRC, need 'aux', set dither */ - if (dm_is_crc_source_dprx(source) || - (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE && - dm_is_crc_source_dprx(cur_crc_src))) { + if (dm_need_dp_aux(source, cur_crc_src)) { struct amdgpu_dm_connector *aconn = NULL; struct drm_connector *connector; struct drm_connector_list_iter conn_iter; @@ -714,23 +771,24 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name) goto cleanup; } - if (!enabled && enable) { - if (dm_is_crc_source_dprx(source)) { - if (drm_dp_start_crc(aux, crtc)) { - DRM_DEBUG_DRIVER("dp start crc failed\n"); - ret = -EINVAL; - goto cleanup; - } + if (dm_crc_source_should_start_dprx(source, cur_crc_src)) { + /* !enabled && enable && is_dprx(source): CRC off → DPRX on */ + if (drm_dp_start_crc(aux, crtc)) { + DRM_DEBUG_DRIVER("dp start crc failed\n"); + ret = -EINVAL; + goto cleanup; + } + } else if (dm_crc_source_should_stop_dprx(source, cur_crc_src)) { + /* enabled && !enable && is_dprx(cur_crc_src): DPRX on → CRC off */ + drm_crtc_vblank_put(crtc); + if (drm_dp_stop_crc(aux)) { + DRM_DEBUG_DRIVER("dp stop crc failed\n"); + ret = -EINVAL; + goto cleanup; } } else if (enabled && !enable) { + /* Non-DPRX source (e.g. CRTC) turning off: release vblank ref */ drm_crtc_vblank_put(crtc); - if (dm_is_crc_source_dprx(source)) { - if (drm_dp_stop_crc(aux)) { - DRM_DEBUG_DRIVER("dp stop crc failed\n"); - ret = -EINVAL; - goto cleanup; - } - } } spin_lock_irq(&drm_dev->event_lock); @@ -767,9 +825,9 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc) { struct dm_crtc_state *crtc_state; struct dc_stream_state *stream_state; - struct drm_device *drm_dev = NULL; + struct drm_device *drm_dev; enum amdgpu_dm_pipe_crc_source cur_crc_src; - struct amdgpu_crtc *acrtc = NULL; + struct amdgpu_crtc *acrtc; uint32_t crcs[3]; unsigned long flags; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h index c9aa0c82038f..8bb8a6f6c148 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h @@ -156,6 +156,12 @@ enum amdgpu_dm_pipe_crc_source dm_parse_crc_source(const char *source); bool dm_is_crc_source_crtc(enum amdgpu_dm_pipe_crc_source src); bool dm_is_crc_source_dprx(enum amdgpu_dm_pipe_crc_source src); bool dm_need_crc_dither(enum amdgpu_dm_pipe_crc_source src); +bool dm_need_dp_aux(enum amdgpu_dm_pipe_crc_source source, + enum amdgpu_dm_pipe_crc_source cur_crc_src); +bool dm_crc_source_should_start_dprx(enum amdgpu_dm_pipe_crc_source source, + enum amdgpu_dm_pipe_crc_source cur_crc_src); +bool dm_crc_source_should_stop_dprx(enum amdgpu_dm_pipe_crc_source source, + enum amdgpu_dm_pipe_crc_source cur_crc_src); #endif #endif /* AMD_DAL_DEV_AMDGPU_DM_AMDGPU_DM_CRC_H_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c index 3dcedaa67ed8..0ad7704800d9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c @@ -34,6 +34,7 @@ #include "amdgpu_dm_plane.h" #include "amdgpu_dm_trace.h" #include "amdgpu_dm_debugfs.h" +#include "amdgpu_dm_kunit_helpers.h" #include "modules/inc/mod_power.h" #define HPD_DETECTION_PERIOD_uS 2000000 @@ -65,6 +66,7 @@ bool amdgpu_dm_crtc_modeset_required(struct drm_crtc_state *crtc_state, { return crtc_state->active && drm_atomic_crtc_needs_modeset(crtc_state); } +EXPORT_IF_KUNIT(amdgpu_dm_crtc_modeset_required); bool amdgpu_dm_crtc_vrr_active_irq(struct amdgpu_crtc *acrtc) @@ -74,6 +76,7 @@ bool amdgpu_dm_crtc_vrr_active_irq(struct amdgpu_crtc *acrtc) acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_FIXED; } +EXPORT_IF_KUNIT(amdgpu_dm_crtc_vrr_active_irq); int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable) { @@ -93,12 +96,14 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable) acrtc->crtc_id, enable ? "en" : "dis", rc); return rc; } +EXPORT_IF_KUNIT(amdgpu_dm_crtc_set_vupdate_irq); bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state) { return dm_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE || dm_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED; } +EXPORT_IF_KUNIT(amdgpu_dm_crtc_vrr_active); /** * amdgpu_dm_crtc_set_static_screen_optimze() - Toggle static screen optimizations. @@ -156,6 +161,7 @@ bool amdgpu_dm_is_headless(struct amdgpu_device *adev) drm_connector_list_iter_end(&iter); return is_headless; } +EXPORT_IF_KUNIT(amdgpu_dm_is_headless); static void amdgpu_dm_idle_worker(struct work_struct *work) { @@ -207,6 +213,7 @@ struct idle_workqueue *idle_create_workqueue(struct amdgpu_device *adev) return idle_work; } +EXPORT_IF_KUNIT(idle_create_workqueue); static void amdgpu_dm_crtc_vblank_control_worker(struct work_struct *work) { @@ -437,13 +444,13 @@ static void amdgpu_dm_crtc_reset_state(struct drm_crtc *crtc) { struct dm_crtc_state *state; + state = kzalloc_obj(*state); + if (!state) + return; + if (crtc->state) amdgpu_dm_crtc_destroy_state(crtc, crtc->state); - state = kzalloc_obj(*state); - if (WARN_ON(!state)) - return; - __drm_atomic_helper_crtc_reset(crtc, &state->base); } @@ -595,12 +602,13 @@ static void amdgpu_dm_crtc_update_crtc_active_planes(struct drm_crtc *crtc, amdgpu_dm_crtc_count_crtc_active_planes(new_crtc_state); } -static bool amdgpu_dm_crtc_helper_mode_fixup(struct drm_crtc *crtc, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +STATIC_IFN_KUNIT bool amdgpu_dm_crtc_helper_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) { return true; } +EXPORT_IF_KUNIT(amdgpu_dm_crtc_helper_mode_fixup); static int amdgpu_dm_crtc_helper_atomic_check(struct drm_crtc *crtc, struct drm_atomic_commit *state) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h index e9fb52f0e66d..d8b004f613ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.h @@ -42,6 +42,12 @@ int amdgpu_dm_crtc_set_vupdate_irq(struct drm_crtc *crtc, bool enable); bool amdgpu_dm_crtc_vrr_active_irq(struct amdgpu_crtc *acrtc); +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +bool amdgpu_dm_crtc_helper_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); +#endif + bool amdgpu_dm_crtc_vrr_active(const struct dm_crtc_state *dm_state); int amdgpu_dm_crtc_enable_vblank(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index 7db38ad3f848..830cf8da06b4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -606,7 +606,7 @@ static int dp_lttpr_status_show(struct seq_file *m, void *unused) break; } - seq_puts(m, "\n"); + seq_putc(m, '\n'); return 0; } @@ -1081,7 +1081,7 @@ static int psr_capability_show(struct seq_file *m, void *data) seq_printf(m, "Driver support: %s", str_yes_no(link->psr_settings.psr_feature_enabled)); if (link->psr_settings.psr_version) seq_printf(m, " [0x%02x]", link->psr_settings.psr_version); - seq_puts(m, "\n"); + seq_putc(m, '\n'); return 0; } @@ -1266,7 +1266,7 @@ static int hdcp_sink_capability_show(struct seq_file *m, void *data) if (!hdcp_cap && !hdcp2_cap) seq_printf(m, "%s ", "None"); - seq_puts(m, "\n"); + seq_putc(m, '\n'); return 0; } @@ -2710,11 +2710,10 @@ static int ips_status_show(struct seq_file *m, void *unused) rcg_count = ips_fw->rcg_exit_count; ips1_count = ips_fw->ips1_exit_count; ips2_count = ips_fw->ips2_exit_count; - seq_printf(m, "exit counts: rcg=%u ips1=%u ips2=%u", + seq_printf(m, "exit counts: rcg=%u ips1=%u ips2=%u\n", rcg_count, ips1_count, ips2_count); - seq_puts(m, "\n"); } return 0; } @@ -2971,7 +2970,7 @@ static ssize_t hdmi_cec_state_write(struct file *f, const char __user *buf, ret = amdgpu_dm_initialize_hdmi_connector(aconnector); if (ret) return ret; - hdmi_cec_set_edid(aconnector); + amdgpu_dm_hdmi_cec_set_edid(aconnector); } else { if (!aconnector->notifier) return -EINVAL; @@ -2982,6 +2981,64 @@ static ssize_t hdmi_cec_state_write(struct file *f, const char __user *buf, return size; } +/** + * hdmi_automation_enable - Enable/Disable HDMI automation feature + * @f: file structure. + * @buf: userspace buffer. set to '1' to enable; '0' to disable automation feature. + * @size: size of buffer from userpsace. + * @pos: unused. + * + * Return size on success, error code on failure + */ +static ssize_t hdmi_automation_enable(struct file *f, const char __user *buf, + size_t size, loff_t *pos) +{ + struct amdgpu_dm_connector *aconnector = file_inode(f)->i_private; + char *wr_buf = NULL; + const uint32_t wr_buf_size = 40; + int max_param_num = 1; + uint8_t param_nums = 0; + long param[2]; + bool hdmi_comp_auto; + + if (size == 0) + return -EINVAL; + + wr_buf = kcalloc(wr_buf_size, sizeof(char), GFP_KERNEL); + if (!wr_buf) + return -ENOSPC; + + if (parse_write_buffer_into_params(wr_buf, wr_buf_size, + (long *)param, buf, + max_param_num, + ¶m_nums)) { + kfree(wr_buf); + return -EINVAL; + } + + if (param_nums <= 0) { + kfree(wr_buf); + DRM_DEBUG_DRIVER("user data not be read\n"); + return -EINVAL; + } + + switch (param[0]) { + case 0: + hdmi_comp_auto = false; + break; + case 1: + default: + hdmi_comp_auto = true; + break; + } + + /* Persist setting across sink re-detection/hotplug. */ + aconnector->hdmi_comp_auto = hdmi_comp_auto; + + kfree(wr_buf); + return size; +} + DEFINE_SHOW_ATTRIBUTE(dp_dsc_fec_support); DEFINE_SHOW_ATTRIBUTE(dmub_fw_state); DEFINE_SHOW_ATTRIBUTE(dmub_tracebuffer); @@ -3099,6 +3156,12 @@ static const struct file_operations dp_mst_link_settings_debugfs_fops = { .llseek = default_llseek }; +static const struct file_operations hdmi_automation_debugfs_fops = { + .owner = THIS_MODULE, + .write = hdmi_automation_enable, + .llseek = default_llseek +}; + static const struct { char *name; const struct file_operations *fops; @@ -3131,7 +3194,8 @@ static const struct { const struct file_operations *fops; } hdmi_debugfs_entries[] = { {"hdcp_sink_capability", &hdcp_sink_capability_fops}, - {"hdmi_cec_state", &hdmi_cec_state_fops} + {"hdmi_cec_state", &hdmi_cec_state_fops}, + {"hdmi_automation", &hdmi_automation_debugfs_fops} }; /* diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c new file mode 100644 index 000000000000..0aa99d1a542f --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.c @@ -0,0 +1,943 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services_types.h" +#include "dc.h" +#include "dc/inc/core_types.h" +#include "dc/dc_dmub_srv.h" +#include "dmub/dmub_srv.h" +#include "dc/inc/hw/dmcu.h" +#include "dc/inc/hw/abm.h" +#include "dal_asic_id.h" + +#include "amdgpu.h" +#include "amdgpu_display.h" +#include "amdgpu_ucode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_dmub.h" +#include "amdgpu_dm_kunit_helpers.h" +#include +#include + +static_assert(AMDGPU_DMUB_NOTIFICATION_MAX == DMUB_NOTIFICATION_MAX, "AMDGPU_DMUB_NOTIFICATION_MAX mismatch"); + +MODULE_FIRMWARE(FIRMWARE_RENOIR_DMUB); +MODULE_FIRMWARE(FIRMWARE_SIENNA_CICHLID_DMUB); +MODULE_FIRMWARE(FIRMWARE_NAVY_FLOUNDER_DMUB); +MODULE_FIRMWARE(FIRMWARE_GREEN_SARDINE_DMUB); +MODULE_FIRMWARE(FIRMWARE_VANGOGH_DMUB); +MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB); +MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB); +MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_314_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_315_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN316_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_0_DMCUB); +MODULE_FIRMWARE(FIRMWARE_DCN_V3_2_1_DMCUB); +MODULE_FIRMWARE(FIRMWARE_DCN_35_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_351_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_36_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_401_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_42_DMUB); +MODULE_FIRMWARE(FIRMWARE_DCN_42B_DMUB); + +/** + * dm_dmub_aux_setconfig_callback - Callback for AUX or SET_CONFIG command. + * @adev: amdgpu_device pointer + * @notify: dmub notification structure + * + * Dmub AUX or SET_CONFIG command completion processing callback + * Copies dmub notification to DM which is to be read by AUX command. + * issuing thread and also signals the event to wake up the thread. + */ +void dm_dmub_aux_setconfig_callback(struct amdgpu_device *adev, + struct dmub_notification *notify) +{ + if (adev->dm.dmub_notify) + memcpy(adev->dm.dmub_notify, notify, sizeof(struct dmub_notification)); + if (notify->type == DMUB_NOTIFICATION_AUX_REPLY) + complete(&adev->dm.dmub_aux_transfer_done); +} +EXPORT_IF_KUNIT(dm_dmub_aux_setconfig_callback); + +void dm_dmub_aux_fused_io_callback(struct amdgpu_device *adev, + struct dmub_notification *notify) +{ + if (!adev || !notify) { + ASSERT(false); + return; + } + + const struct dmub_cmd_fused_request *req = ¬ify->fused_request; + const uint8_t ddc_line = req->u.aux.ddc_line; + + if (ddc_line >= ARRAY_SIZE(adev->dm.fused_io)) { + ASSERT(false); + return; + } + + struct fused_io_sync *sync = &adev->dm.fused_io[ddc_line]; + + static_assert(sizeof(*req) <= sizeof(sync->reply_data), "Size mismatch"); + memcpy(sync->reply_data, req, sizeof(*req)); + complete(&sync->replied); +} +EXPORT_IF_KUNIT(dm_dmub_aux_fused_io_callback); + +/** + * dm_register_dmub_notify_callback - Sets callback for DMUB notify + * @adev: amdgpu_device pointer + * @type: Type of dmub notification + * @callback: Dmub interrupt callback function + * @dmub_int_thread_offload: offload indicator + * + * API to register a dmub callback handler for a dmub notification + * Also sets indicator whether callback processing to be offloaded. + * to dmub interrupt handling thread + * Return: true if successfully registered, false if there is existing registration + */ +bool dm_register_dmub_notify_callback(struct amdgpu_device *adev, + enum dmub_notification_type type, + dmub_notify_interrupt_callback_t callback, + bool dmub_int_thread_offload) +{ + if (!callback || type >= ARRAY_SIZE(adev->dm.dmub_thread_offload)) + return false; + + adev->dm.dmub_callback[type] = callback; + adev->dm.dmub_thread_offload[type] = dmub_int_thread_offload; + + return true; +} +EXPORT_IF_KUNIT(dm_register_dmub_notify_callback); + +int dm_dmub_hw_init(struct amdgpu_device *adev) +{ + const struct dmcub_firmware_header_v1_0 *hdr; + struct dmub_srv *dmub_srv = adev->dm.dmub_srv; + struct dmub_srv_fb_info *fb_info = adev->dm.dmub_fb_info; + const struct firmware *dmub_fw = adev->dm.dmub_fw; + struct dc *dc = adev->dm.dc; + struct dmcu *dmcu = adev->dm.dc->res_pool->dmcu; + struct abm *abm = adev->dm.dc->res_pool->abm; + struct dc_context *ctx = adev->dm.dc->ctx; + struct dmub_srv_hw_params hw_params; + enum dmub_status status; + const unsigned char *fw_inst_const, *fw_bss_data; + u32 i, fw_inst_const_size, fw_bss_data_size; + bool has_hw_support; + + if (!dmub_srv) + /* DMUB isn't supported on the ASIC. */ + return 0; + + if (!fb_info) { + drm_err(adev_to_drm(adev), "No framebuffer info for DMUB service.\n"); + return -EINVAL; + } + + if (!dmub_fw) { + /* Firmware required for DMUB support. */ + drm_err(adev_to_drm(adev), "No firmware provided for DMUB.\n"); + return -EINVAL; + } + + /* initialize register offsets for ASICs with runtime initialization available */ + if (dmub_srv->hw_funcs.init_reg_offsets) + dmub_srv->hw_funcs.init_reg_offsets(dmub_srv, ctx); + + status = dmub_srv_has_hw_support(dmub_srv, &has_hw_support); + if (status != DMUB_STATUS_OK) { + drm_err(adev_to_drm(adev), "Error checking HW support for DMUB: %d\n", status); + return -EINVAL; + } + + if (!has_hw_support) { + drm_info(adev_to_drm(adev), "DMUB unsupported on ASIC\n"); + return 0; + } + + /* Reset DMCUB if it was previously running - before we overwrite its memory. */ + status = dmub_srv_hw_reset(dmub_srv); + if (status != DMUB_STATUS_OK) + drm_warn(adev_to_drm(adev), "Error resetting DMUB HW: %d\n", status); + + hdr = (const struct dmcub_firmware_header_v1_0 *)dmub_fw->data; + + fw_inst_const = dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + PSP_HEADER_BYTES_256; + + fw_bss_data = dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + le32_to_cpu(hdr->inst_const_bytes); + + /* Copy firmware and bios info into FB memory. */ + fw_inst_const_size = adev->dm.fw_inst_size; + + fw_bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + + /* if adev->firmware.load_type == AMDGPU_FW_LOAD_PSP, + * amdgpu_ucode_init_single_fw will load dmub firmware + * fw_inst_const part to cw0; otherwise, the firmware back door load + * will be done by dm_dmub_hw_init + */ + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { + memcpy(fb_info->fb[DMUB_WINDOW_0_INST_CONST].cpu_addr, fw_inst_const, + fw_inst_const_size); + } + + if (fw_bss_data_size) + memcpy(fb_info->fb[DMUB_WINDOW_2_BSS_DATA].cpu_addr, + fw_bss_data, fw_bss_data_size); + + /* Copy firmware bios info into FB memory. */ + memcpy(fb_info->fb[DMUB_WINDOW_3_VBIOS].cpu_addr, adev->bios, + adev->bios_size); + + /* Reset regions that need to be reset. */ + memset(fb_info->fb[DMUB_WINDOW_4_MAILBOX].cpu_addr, 0, + fb_info->fb[DMUB_WINDOW_4_MAILBOX].size); + + memset(fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].cpu_addr, 0, + fb_info->fb[DMUB_WINDOW_5_TRACEBUFF].size); + + memset(fb_info->fb[DMUB_WINDOW_6_FW_STATE].cpu_addr, 0, + fb_info->fb[DMUB_WINDOW_6_FW_STATE].size); + + memset(fb_info->fb[DMUB_WINDOW_SHARED_STATE].cpu_addr, 0, + fb_info->fb[DMUB_WINDOW_SHARED_STATE].size); + + /* Initialize hardware. */ + memset(&hw_params, 0, sizeof(hw_params)); + hw_params.soc_fb_info.fb_base = adev->gmc.fb_start; + hw_params.soc_fb_info.fb_offset = adev->vm_manager.vram_base_offset; + + /* backdoor load firmware and trigger dmub running */ + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) + hw_params.load_inst_const = true; + + if (dmcu) + hw_params.psp_version = dmcu->psp_version; + + for (i = 0; i < fb_info->num_fb; ++i) + hw_params.fb[i] = &fb_info->fb[i]; + + /* Enable usb4 dpia in the FW APU */ + if (dc->caps.is_apu && + dc->res_pool->usb4_dpia_count != 0 && + !dc->debug.dpia_debug.bits.disable_dpia) { + hw_params.dpia_supported = true; + hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia; + hw_params.dpia_hpd_int_enable_supported = false; + hw_params.enable_non_transparent_setconfig = dc->config.consolidated_dpia_dp_lt; + hw_params.disable_dpia_bw_allocation = !dc->config.usb4_bw_alloc_support; + } + + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 5, 0): + case IP_VERSION(3, 5, 1): + case IP_VERSION(3, 6, 0): + case IP_VERSION(4, 2, 0): + case IP_VERSION(4, 2, 1): + hw_params.ips_sequential_ono = adev->external_rev_id > 0x10; + hw_params.lower_hbr3_phy_ssc = true; + break; + default: + break; + } + + status = dmub_srv_hw_init(dmub_srv, &hw_params); + if (status != DMUB_STATUS_OK) { + drm_err(adev_to_drm(adev), "Error initializing DMUB HW: %d\n", status); + return -EINVAL; + } + + /* Wait for firmware load to finish. */ + status = dmub_srv_wait_for_auto_load(dmub_srv, 100000); + if (status != DMUB_STATUS_OK) + drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status); + + /* Init DMCU and ABM if available. */ + if (dmcu && abm) { + dmcu->funcs->dmcu_init(dmcu); + abm->dmcu_is_running = dmcu->funcs->is_dmcu_initialized(dmcu); + } + + if (!adev->dm.dc->ctx->dmub_srv) + adev->dm.dc->ctx->dmub_srv = dc_dmub_srv_create(adev->dm.dc, dmub_srv); + if (!adev->dm.dc->ctx->dmub_srv) { + drm_err(adev_to_drm(adev), "Couldn't allocate DC DMUB server!\n"); + return -ENOMEM; + } + + drm_info(adev_to_drm(adev), "DMUB hardware initialized: version=0x%08X\n", + adev->dm.dmcub_fw_version); + + /* Keeping sanity checks off if + * DCN31 >= 4.0.59.0 + * DCN314 >= 8.0.16.0 + * Otherwise, turn on sanity checks + */ + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + if (adev->dm.dmcub_fw_version && + adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) && + adev->dm.dmcub_fw_version < DMUB_FW_VERSION(4, 0, 59)) + adev->dm.dc->debug.sanity_checks = true; + break; + case IP_VERSION(3, 1, 4): + if (adev->dm.dmcub_fw_version && + adev->dm.dmcub_fw_version >= DMUB_FW_VERSION(4, 0, 0) && + adev->dm.dmcub_fw_version < DMUB_FW_VERSION(8, 0, 16)) + adev->dm.dc->debug.sanity_checks = true; + break; + default: + break; + } + + return 0; +} +EXPORT_IF_KUNIT(dm_dmub_hw_init); + +void dm_dmub_hw_resume(struct amdgpu_device *adev) +{ + struct dmub_srv *dmub_srv = adev->dm.dmub_srv; + enum dmub_status status; + bool init; + int r; + + if (!dmub_srv) { + /* DMUB isn't supported on the ASIC. */ + return; + } + + status = dmub_srv_is_hw_init(dmub_srv, &init); + if (status != DMUB_STATUS_OK) + drm_warn(adev_to_drm(adev), "DMUB hardware init check failed: %d\n", status); + + if (status == DMUB_STATUS_OK && init) { + /* Wait for firmware load to finish. */ + status = dmub_srv_wait_for_auto_load(dmub_srv, 100000); + if (status != DMUB_STATUS_OK) + drm_warn(adev_to_drm(adev), "Wait for DMUB auto-load failed: %d\n", status); + } else { + /* Perform the full hardware initialization. */ + r = dm_dmub_hw_init(adev); + if (r) + drm_err(adev_to_drm(adev), "DMUB interface failed to initialize: status=%d\n", r); + } +} +EXPORT_IF_KUNIT(dm_dmub_hw_resume); + +static enum dmub_status +dm_dmub_send_vbios_gpint_command(struct amdgpu_device *adev, + enum dmub_gpint_command command_code, + uint16_t param, + uint32_t timeout_us) +{ + union dmub_gpint_data_register reg, test; + uint32_t i; + + /* Assume that VBIOS DMUB is ready to take commands */ + + reg.bits.status = 1; + reg.bits.command_code = command_code; + reg.bits.param = param; + + cgs_write_register(adev->dm.cgs_device, 0x34c0 + 0x01f8, reg.all); + + for (i = 0; i < timeout_us; ++i) { + udelay(1); + + /* Check if our GPINT got acked */ + reg.bits.status = 0; + test = (union dmub_gpint_data_register) + cgs_read_register(adev->dm.cgs_device, 0x34c0 + 0x01f8); + + if (test.all == reg.all) + return DMUB_STATUS_OK; + } + + return DMUB_STATUS_TIMEOUT; +} + +static void *dm_dmub_get_vbios_bounding_box(struct amdgpu_device *adev) +{ + void *bb; + long long addr; + unsigned int bb_size; + int i = 0; + uint16_t chunk; + enum dmub_gpint_command send_addrs[] = { + DMUB_GPINT__SET_BB_ADDR_WORD0, + DMUB_GPINT__SET_BB_ADDR_WORD1, + DMUB_GPINT__SET_BB_ADDR_WORD2, + DMUB_GPINT__SET_BB_ADDR_WORD3, + }; + enum dmub_status ret; + + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(4, 0, 1): + bb_size = sizeof(struct dml2_soc_bb); + break; + case IP_VERSION(4, 2, 0): + case IP_VERSION(4, 2, 1): + bb_size = sizeof(struct dml2_soc_bb); + break; + default: + return NULL; + } + + bb = dm_allocate_gpu_mem(adev, + DC_MEM_ALLOC_TYPE_GART, + bb_size, + &addr); + if (!bb) + return NULL; + + for (i = 0; i < 4; i++) { + /* Extract 16-bit chunk */ + chunk = ((uint64_t) addr >> (i * 16)) & 0xFFFF; + /* Send the chunk */ + ret = dm_dmub_send_vbios_gpint_command(adev, send_addrs[i], chunk, 30000); + if (ret != DMUB_STATUS_OK) + goto free_bb; + } + + /* Now ask DMUB to copy the bb */ + ret = dm_dmub_send_vbios_gpint_command(adev, DMUB_GPINT__BB_COPY, 1, 200000); + if (ret != DMUB_STATUS_OK) + goto free_bb; + + return bb; + +free_bb: + dm_free_gpu_mem(adev, DC_MEM_ALLOC_TYPE_GART, (void *) bb); + return NULL; + +} + +enum dmub_ips_disable_type dm_get_default_ips_mode( + struct amdgpu_device *adev) +{ + enum dmub_ips_disable_type ret = DMUB_IPS_ENABLE; + + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(3, 5, 0): + case IP_VERSION(3, 6, 0): + case IP_VERSION(3, 5, 1): + ret = DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF; + break; + default: + /* ASICs older than DCN35 do not have IPSs */ + if (amdgpu_ip_version(adev, DCE_HWIP, 0) < IP_VERSION(3, 5, 0)) + ret = DMUB_IPS_DISABLE_ALL; + break; + } + + return ret; +} +EXPORT_IF_KUNIT(dm_get_default_ips_mode); + +static uint32_t amdgpu_dm_dmub_reg_read(void *ctx, uint32_t address) +{ + struct amdgpu_device *adev = ctx; + + return dm_read_reg(adev->dm.dc->ctx, address); +} + +static void amdgpu_dm_dmub_reg_write(void *ctx, uint32_t address, + uint32_t value) +{ + struct amdgpu_device *adev = ctx; + + return dm_write_reg(adev->dm.dc->ctx, address, value); +} + +int dm_dmub_sw_init(struct amdgpu_device *adev) +{ + struct dmub_srv_create_params create_params; + struct dmub_srv_fw_meta_info_params fw_meta_info_params; + struct dmub_srv_region_params region_params; + struct dmub_srv_region_info region_info; + struct dmub_srv_memory_params memory_params; + struct dmub_fw_meta_info fw_info; + struct dmub_srv_fb_info *fb_info; + struct dmub_srv *dmub_srv; + const struct dmcub_firmware_header_v1_0 *hdr; + enum dmub_asic dmub_asic; + enum dmub_status status; + static enum dmub_window_memory_type window_memory_type[DMUB_WINDOW_TOTAL] = { + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_0_INST_CONST */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_1_STACK */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_2_BSS_DATA */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_3_VBIOS */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_4_MAILBOX */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_5_TRACEBUFF */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_6_FW_STATE */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_7_SCRATCH_MEM */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_IB_MEM */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_SHARED_STATE */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_LSDMA_BUFFER */ + DMUB_WINDOW_MEMORY_TYPE_FB, /* DMUB_WINDOW_CURSOR_OFFLOAD */ + }; + int r; + + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(2, 1, 0): + dmub_asic = DMUB_ASIC_DCN21; + break; + case IP_VERSION(3, 0, 0): + dmub_asic = DMUB_ASIC_DCN30; + break; + case IP_VERSION(3, 0, 1): + dmub_asic = DMUB_ASIC_DCN301; + break; + case IP_VERSION(3, 0, 2): + dmub_asic = DMUB_ASIC_DCN302; + break; + case IP_VERSION(3, 0, 3): + dmub_asic = DMUB_ASIC_DCN303; + break; + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31; + break; + case IP_VERSION(3, 1, 4): + dmub_asic = DMUB_ASIC_DCN314; + break; + case IP_VERSION(3, 1, 5): + dmub_asic = DMUB_ASIC_DCN315; + break; + case IP_VERSION(3, 1, 6): + dmub_asic = DMUB_ASIC_DCN316; + break; + case IP_VERSION(3, 2, 0): + dmub_asic = DMUB_ASIC_DCN32; + break; + case IP_VERSION(3, 2, 1): + dmub_asic = DMUB_ASIC_DCN321; + break; + case IP_VERSION(3, 5, 0): + case IP_VERSION(3, 5, 1): + dmub_asic = DMUB_ASIC_DCN35; + break; + case IP_VERSION(3, 6, 0): + dmub_asic = DMUB_ASIC_DCN36; + break; + case IP_VERSION(4, 0, 1): + dmub_asic = DMUB_ASIC_DCN401; + break; + case IP_VERSION(4, 2, 0): + dmub_asic = DMUB_ASIC_DCN42; + break; + case IP_VERSION(4, 2, 1): + dmub_asic = DMUB_ASIC_DCN42B; + break; + default: + /* ASIC doesn't support DMUB. */ + return 0; + } + + hdr = (const struct dmcub_firmware_header_v1_0 *)adev->dm.dmub_fw->data; + adev->dm.dmcub_fw_version = le32_to_cpu(hdr->header.ucode_version); + + if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { + adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].ucode_id = + AMDGPU_UCODE_ID_DMCUB; + adev->firmware.ucode[AMDGPU_UCODE_ID_DMCUB].fw = + adev->dm.dmub_fw; + adev->firmware.fw_size += + ALIGN(le32_to_cpu(hdr->inst_const_bytes), PAGE_SIZE); + + drm_info(adev_to_drm(adev), "Loading DMUB firmware via PSP: version=0x%08X\n", + adev->dm.dmcub_fw_version); + } + + + adev->dm.dmub_srv = kzalloc_obj(*adev->dm.dmub_srv); + dmub_srv = adev->dm.dmub_srv; + + if (!dmub_srv) { + drm_err(adev_to_drm(adev), "Failed to allocate DMUB service!\n"); + return -ENOMEM; + } + + memset(&create_params, 0, sizeof(create_params)); + create_params.user_ctx = adev; + create_params.funcs.reg_read = amdgpu_dm_dmub_reg_read; + create_params.funcs.reg_write = amdgpu_dm_dmub_reg_write; + create_params.asic = dmub_asic; + + /* Create the DMUB service. */ + status = dmub_srv_create(dmub_srv, &create_params); + if (status != DMUB_STATUS_OK) { + drm_err(adev_to_drm(adev), "Error creating DMUB service: %d\n", status); + return -EINVAL; + } + + /* Extract the FW meta info. */ + memset(&fw_meta_info_params, 0, sizeof(fw_meta_info_params)); + + fw_meta_info_params.inst_const_size = le32_to_cpu(hdr->inst_const_bytes) - + PSP_HEADER_BYTES_256; + fw_meta_info_params.bss_data_size = le32_to_cpu(hdr->bss_data_bytes); + fw_meta_info_params.fw_inst_const = adev->dm.dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + PSP_HEADER_BYTES_256; + fw_meta_info_params.fw_bss_data = fw_meta_info_params.bss_data_size ? adev->dm.dmub_fw->data + + le32_to_cpu(hdr->header.ucode_array_offset_bytes) + + le32_to_cpu(hdr->inst_const_bytes) : NULL; + fw_meta_info_params.custom_psp_footer_size = 0; + + status = dmub_srv_get_fw_meta_info_from_raw_fw(&fw_meta_info_params, &fw_info); + if (status != DMUB_STATUS_OK) { + /* Skip returning early, just log the error. */ + drm_err(adev_to_drm(adev), "Error getting DMUB FW meta info: %d\n", status); + } + + /* Calculate the size of all the regions for the DMUB service. */ + memset(®ion_params, 0, sizeof(region_params)); + + region_params.inst_const_size = fw_meta_info_params.inst_const_size; + region_params.bss_data_size = fw_meta_info_params.bss_data_size; + region_params.vbios_size = adev->bios_size; + region_params.fw_bss_data = fw_meta_info_params.fw_bss_data; + region_params.fw_inst_const = fw_meta_info_params.fw_inst_const; + region_params.window_memory_type = window_memory_type; + region_params.fw_info = (status == DMUB_STATUS_OK) ? &fw_info : NULL; + + status = dmub_srv_calc_region_info(dmub_srv, ®ion_params, + ®ion_info); + + if (status != DMUB_STATUS_OK) { + drm_err(adev_to_drm(adev), "Error calculating DMUB region info: %d\n", status); + return -EINVAL; + } + + /* + * Allocate a framebuffer based on the total size of all the regions. + * TODO: Move this into GART. + */ + r = amdgpu_bo_create_kernel(adev, region_info.fb_size, PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM | + AMDGPU_GEM_DOMAIN_GTT, + &adev->dm.dmub_bo, + &adev->dm.dmub_bo_gpu_addr, + &adev->dm.dmub_bo_cpu_addr); + if (r) + return r; + + /* Rebase the regions on the framebuffer address. */ + memset(&memory_params, 0, sizeof(memory_params)); + memory_params.cpu_fb_addr = adev->dm.dmub_bo_cpu_addr; + memory_params.gpu_fb_addr = adev->dm.dmub_bo_gpu_addr; + memory_params.region_info = ®ion_info; + memory_params.window_memory_type = window_memory_type; + + adev->dm.dmub_fb_info = kzalloc_obj(*adev->dm.dmub_fb_info); + fb_info = adev->dm.dmub_fb_info; + + if (!fb_info) { + drm_err(adev_to_drm(adev), + "Failed to allocate framebuffer info for DMUB service!\n"); + return -ENOMEM; + } + + status = dmub_srv_calc_mem_info(dmub_srv, &memory_params, fb_info); + if (status != DMUB_STATUS_OK) { + drm_err(adev_to_drm(adev), "Error calculating DMUB FB info: %d\n", status); + return -EINVAL; + } + + adev->dm.bb_from_dmub = dm_dmub_get_vbios_bounding_box(adev); + adev->dm.fw_inst_size = fw_meta_info_params.inst_const_size; + + return 0; +} +EXPORT_IF_KUNIT(dm_dmub_sw_init); + +int dm_init_microcode(struct amdgpu_device *adev) +{ + char *fw_name_dmub; + int r; + + switch (amdgpu_ip_version(adev, DCE_HWIP, 0)) { + case IP_VERSION(2, 1, 0): + fw_name_dmub = FIRMWARE_RENOIR_DMUB; + if (ASICREV_IS_GREEN_SARDINE(adev->external_rev_id)) + fw_name_dmub = FIRMWARE_GREEN_SARDINE_DMUB; + break; + case IP_VERSION(3, 0, 0): + if (amdgpu_ip_version(adev, GC_HWIP, 0) == IP_VERSION(10, 3, 0)) + fw_name_dmub = FIRMWARE_SIENNA_CICHLID_DMUB; + else + fw_name_dmub = FIRMWARE_NAVY_FLOUNDER_DMUB; + break; + case IP_VERSION(3, 0, 1): + fw_name_dmub = FIRMWARE_VANGOGH_DMUB; + break; + case IP_VERSION(3, 0, 2): + fw_name_dmub = FIRMWARE_DIMGREY_CAVEFISH_DMUB; + break; + case IP_VERSION(3, 0, 3): + fw_name_dmub = FIRMWARE_BEIGE_GOBY_DMUB; + break; + case IP_VERSION(3, 1, 2): + case IP_VERSION(3, 1, 3): + fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB; + break; + case IP_VERSION(3, 1, 4): + fw_name_dmub = FIRMWARE_DCN_314_DMUB; + break; + case IP_VERSION(3, 1, 5): + fw_name_dmub = FIRMWARE_DCN_315_DMUB; + break; + case IP_VERSION(3, 1, 6): + fw_name_dmub = FIRMWARE_DCN316_DMUB; + break; + case IP_VERSION(3, 2, 0): + fw_name_dmub = FIRMWARE_DCN_V3_2_0_DMCUB; + break; + case IP_VERSION(3, 2, 1): + fw_name_dmub = FIRMWARE_DCN_V3_2_1_DMCUB; + break; + case IP_VERSION(3, 5, 0): + fw_name_dmub = FIRMWARE_DCN_35_DMUB; + break; + case IP_VERSION(3, 5, 1): + fw_name_dmub = FIRMWARE_DCN_351_DMUB; + break; + case IP_VERSION(3, 6, 0): + fw_name_dmub = FIRMWARE_DCN_36_DMUB; + break; + case IP_VERSION(4, 0, 1): + fw_name_dmub = FIRMWARE_DCN_401_DMUB; + break; + case IP_VERSION(4, 2, 0): + fw_name_dmub = FIRMWARE_DCN_42_DMUB; + break; + case IP_VERSION(4, 2, 1): + fw_name_dmub = FIRMWARE_DCN_42B_DMUB; + break; + default: + /* ASIC doesn't support DMUB. */ + return 0; + } + r = amdgpu_ucode_request(adev, &adev->dm.dmub_fw, AMDGPU_UCODE_REQUIRED, + "%s", fw_name_dmub); + return r; +} +EXPORT_IF_KUNIT(dm_init_microcode); + +int amdgpu_dm_process_dmub_aux_transfer_sync( + struct dc_context *ctx, + unsigned int link_index, + struct aux_payload *payload, + enum aux_return_code_type *operation_result) +{ + struct amdgpu_device *adev = ctx->driver_context; + struct dmub_notification *p_notify = adev->dm.dmub_notify; + int ret = -1; + + mutex_lock(&adev->dm.dpia_aux_lock); + if (!dc_process_dmub_aux_transfer_async(ctx->dc, link_index, payload)) { + *operation_result = AUX_RET_ERROR_ENGINE_ACQUIRE; + goto out; + } + + if (!wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) { + drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!"); + *operation_result = AUX_RET_ERROR_TIMEOUT; + goto out; + } + + if (p_notify->result != AUX_RET_SUCCESS) { + /* + * Transient states before tunneling is enabled could + * lead to this error. We can ignore this for now. + */ + if (p_notify->result == AUX_RET_ERROR_PROTOCOL_ERROR) { + drm_warn(adev_to_drm(adev), "DPIA AUX failed on 0x%x(%d), error %d\n", + payload->address, payload->length, + p_notify->result); + } + *operation_result = p_notify->result; + goto out; + } + + payload->reply[0] = adev->dm.dmub_notify->aux_reply.command & 0xF; + if (adev->dm.dmub_notify->aux_reply.command & 0xF0) + /* The reply is stored in the top nibble of the command. */ + payload->reply[0] = (adev->dm.dmub_notify->aux_reply.command >> 4) & 0xF; + + /*write req may receive a byte indicating partially written number as well*/ + if (p_notify->aux_reply.length && payload->data) { + /* Bound the reply to the scratch buffer it was read into. */ + ret = min((uint32_t)p_notify->aux_reply.length, + (uint32_t)sizeof(p_notify->aux_reply.data)); + + /* + * During a write-status-update retry the caller zeroes + * payload->length while still expecting the partial-write + * status byte in payload->data (see dce_aux_transfer_with_retries), + * so only clamp to payload->length for regular transfers. + */ + if (!payload->write_status_update) + ret = min(ret, payload->length); + + memcpy(payload->data, p_notify->aux_reply.data, ret); + } else { + /* success */ + ret = p_notify->aux_reply.length; + } + + *operation_result = p_notify->result; +out: + reinit_completion(&adev->dm.dmub_aux_transfer_done); + mutex_unlock(&adev->dm.dpia_aux_lock); + return ret; +} + +static void abort_fused_io( + struct dc_context *ctx, + const struct dmub_cmd_fused_request *request +) +{ + union dmub_rb_cmd command = { 0 }; + struct dmub_rb_cmd_fused_io *io = &command.fused_io; + + io->header.type = DMUB_CMD__FUSED_IO; + io->header.sub_type = DMUB_CMD__FUSED_IO_ABORT; + io->header.payload_bytes = sizeof(*io) - sizeof(io->header); + io->request = *request; + dm_execute_dmub_cmd(ctx, &command, DM_DMUB_WAIT_TYPE_NO_WAIT); +} + +static bool execute_fused_io( + struct amdgpu_device *dev, + struct dc_context *ctx, + union dmub_rb_cmd *commands, + uint8_t count, + uint32_t timeout_us +) +{ + const uint8_t ddc_line = commands[0].fused_io.request.u.aux.ddc_line; + + if (ddc_line >= ARRAY_SIZE(dev->dm.fused_io)) + return false; + + struct fused_io_sync *sync = &dev->dm.fused_io[ddc_line]; + struct dmub_rb_cmd_fused_io *first = &commands[0].fused_io; + const bool result = dm_execute_dmub_cmd_list(ctx, count, commands, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY) + && first->header.ret_status + && first->request.status == FUSED_REQUEST_STATUS_SUCCESS; + + if (!result) + return false; + + while (wait_for_completion_timeout(&sync->replied, usecs_to_jiffies(timeout_us))) { + reinit_completion(&sync->replied); + + struct dmub_cmd_fused_request *reply = (struct dmub_cmd_fused_request *) sync->reply_data; + + static_assert(sizeof(*reply) <= sizeof(sync->reply_data), "Size mismatch"); + + if (reply->identifier == first->request.identifier) { + first->request = *reply; + return true; + } + } + + reinit_completion(&sync->replied); + first->request.status = FUSED_REQUEST_STATUS_TIMEOUT; + abort_fused_io(ctx, &first->request); + return false; +} + +bool amdgpu_dm_execute_fused_io( + struct amdgpu_device *dev, + struct dc_link *link, + union dmub_rb_cmd *commands, + uint8_t count, + uint32_t timeout_us) +{ + struct amdgpu_display_manager *dm = &dev->dm; + + mutex_lock(&dm->dpia_aux_lock); + + const bool result = execute_fused_io(dev, link->ctx, commands, count, timeout_us); + + mutex_unlock(&dm->dpia_aux_lock); + return result; +} + +int amdgpu_dm_process_dmub_set_config_sync( + struct dc_context *ctx, + unsigned int link_index, + struct set_config_cmd_payload *payload, + enum set_config_status *operation_result) +{ + struct amdgpu_device *adev = ctx->driver_context; + bool is_cmd_complete; + int ret; + + mutex_lock(&adev->dm.dpia_aux_lock); + is_cmd_complete = dc_process_dmub_set_config_async(ctx->dc, + link_index, payload, adev->dm.dmub_notify); + + if (is_cmd_complete || wait_for_completion_timeout(&adev->dm.dmub_aux_transfer_done, 10 * HZ)) { + ret = 0; + *operation_result = adev->dm.dmub_notify->sc_status; + } else { + drm_err(adev_to_drm(adev), "wait_for_completion_timeout timeout!"); + ret = -1; + *operation_result = SET_CONFIG_UNKNOWN_ERROR; + } + + if (!is_cmd_complete) + reinit_completion(&adev->dm.dmub_aux_transfer_done); + mutex_unlock(&adev->dm.dpia_aux_lock); + return ret; +} + +bool dm_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type) +{ + struct amdgpu_device *adev = ctx->driver_context; + + guard(spinlock_irqsave)(&adev->dm.dmub_lock); + return dc_dmub_srv_cmd_run(ctx->dmub_srv, cmd, wait_type); +} + +bool dm_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type) +{ + struct amdgpu_device *adev = ctx->driver_context; + + guard(spinlock_irqsave)(&adev->dm.dmub_lock); + return dc_dmub_srv_cmd_run_list(ctx->dmub_srv, count, cmd, wait_type); +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h new file mode 100644 index 000000000000..a4a03e40ec37 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_dmub.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef AMDGPU_DM_AMDGPU_DM_DMUB_H_ +#define AMDGPU_DM_AMDGPU_DM_DMUB_H_ + +#include "amdgpu.h" + +void dm_dmub_aux_setconfig_callback(struct amdgpu_device *adev, + struct dmub_notification *notify); +void dm_dmub_aux_fused_io_callback(struct amdgpu_device *adev, + struct dmub_notification *notify); +bool dm_register_dmub_notify_callback(struct amdgpu_device *adev, + enum dmub_notification_type type, + dmub_notify_interrupt_callback_t callback, + bool dmub_int_thread_offload); +int dm_dmub_hw_init(struct amdgpu_device *adev); +void dm_dmub_hw_resume(struct amdgpu_device *adev); +enum dmub_ips_disable_type dm_get_default_ips_mode(struct amdgpu_device *adev); +int dm_dmub_sw_init(struct amdgpu_device *adev); +int dm_init_microcode(struct amdgpu_device *adev); + +#define FIRMWARE_RENOIR_DMUB "amdgpu/renoir_dmcub.bin" +#define FIRMWARE_SIENNA_CICHLID_DMUB "amdgpu/sienna_cichlid_dmcub.bin" +#define FIRMWARE_NAVY_FLOUNDER_DMUB "amdgpu/navy_flounder_dmcub.bin" +#define FIRMWARE_GREEN_SARDINE_DMUB "amdgpu/green_sardine_dmcub.bin" +#define FIRMWARE_VANGOGH_DMUB "amdgpu/vangogh_dmcub.bin" +#define FIRMWARE_DIMGREY_CAVEFISH_DMUB "amdgpu/dimgrey_cavefish_dmcub.bin" +#define FIRMWARE_BEIGE_GOBY_DMUB "amdgpu/beige_goby_dmcub.bin" +#define FIRMWARE_YELLOW_CARP_DMUB "amdgpu/yellow_carp_dmcub.bin" +#define FIRMWARE_DCN_314_DMUB "amdgpu/dcn_3_1_4_dmcub.bin" +#define FIRMWARE_DCN_315_DMUB "amdgpu/dcn_3_1_5_dmcub.bin" +#define FIRMWARE_DCN316_DMUB "amdgpu/dcn_3_1_6_dmcub.bin" +#define FIRMWARE_DCN_V3_2_0_DMCUB "amdgpu/dcn_3_2_0_dmcub.bin" +#define FIRMWARE_DCN_V3_2_1_DMCUB "amdgpu/dcn_3_2_1_dmcub.bin" +#define FIRMWARE_DCN_35_DMUB "amdgpu/dcn_3_5_dmcub.bin" +#define FIRMWARE_DCN_351_DMUB "amdgpu/dcn_3_5_1_dmcub.bin" +#define FIRMWARE_DCN_36_DMUB "amdgpu/dcn_3_6_dmcub.bin" +#define FIRMWARE_DCN_401_DMUB "amdgpu/dcn_4_0_1_dmcub.bin" +#define FIRMWARE_DCN_42_DMUB "amdgpu/dcn_4_2_dmcub.bin" +#define FIRMWARE_DCN_42B_DMUB "amdgpu/dcn_4_2_1_dmcub.bin" +#define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin" +#define FIRMWARE_NAVI12_DMCU "amdgpu/navi12_dmcu.bin" + +#endif /* AMDGPU_DM_AMDGPU_DM_DMUB_H_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c index 4c164ae4a4f9..5dbeb1e017d4 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c @@ -182,6 +182,70 @@ void process_output(struct hdcp_workqueue *hdcp_work) } EXPORT_IF_KUNIT(process_output); +STATIC_IFN_KUNIT +bool hdcp_get_content_protection_from_status( + unsigned int hdcp_content_type, + enum mod_hdcp_encryption_status encryption_status, + unsigned int *content_protection) +{ + if (encryption_status == MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) { + *content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; + return true; + } + + if (hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE0 && + encryption_status <= MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) { + *content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; + return true; + } + + if (hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE1 && + encryption_status == MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) { + *content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED; + return true; + } + + return false; +} +EXPORT_IF_KUNIT(hdcp_get_content_protection_from_status); + +STATIC_IFN_KUNIT +void hdcp_get_link_display_adjustments( + bool enable_encryption, + u8 content_type, + bool fused_io_supported, + bool hdcp_lc_force_fw_enable, + bool hdcp_lc_enable_sw_fallback, + struct mod_hdcp_link_adjustment *link_adjust, + struct mod_hdcp_display_adjustment *display_adjust) +{ + memset(link_adjust, 0, sizeof(*link_adjust)); + memset(display_adjust, 0, sizeof(*display_adjust)); + + if (!enable_encryption) { + display_adjust->disable = + MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION; + return; + } + + display_adjust->disable = MOD_HDCP_DISPLAY_NOT_DISABLE; + link_adjust->auth_delay = 2; + link_adjust->retry_limit = MAX_NUM_OF_ATTEMPTS; + + if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) { + link_adjust->hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0; + } else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1) { + link_adjust->hdcp1.disable = 1; + link_adjust->hdcp2.force_type = MOD_HDCP_FORCE_TYPE_1; + } + + link_adjust->hdcp2.use_fw_locality_check = + fused_io_supported || hdcp_lc_force_fw_enable; + link_adjust->hdcp2.use_sw_locality_fallback = + hdcp_lc_enable_sw_fallback; +} +EXPORT_IF_KUNIT(hdcp_get_link_display_adjustments); + static void link_lock(struct hdcp_workqueue *work, bool lock) { int i = 0; @@ -212,8 +276,11 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, drm_connector_put(&hdcp_w->aconnector[conn_index]->base); hdcp_w->aconnector[conn_index] = aconnector; - memset(&link_adjust, 0, sizeof(link_adjust)); - memset(&display_adjust, 0, sizeof(display_adjust)); + hdcp_get_link_display_adjustments(enable_encryption, content_type, + dc->caps.fused_io_supported, + dc->debug.hdcp_lc_force_fw_enable, + dc->debug.hdcp_lc_enable_sw_fallback, + &link_adjust, &display_adjust); if (enable_encryption) { /* Explicitly set the saved SRM as sysfs call will be after we already enabled hdcp @@ -224,25 +291,9 @@ void hdcp_update_display(struct hdcp_workqueue *hdcp_work, hdcp_work->srm_size, &hdcp_work->srm_version); - display_adjust.disable = MOD_HDCP_DISPLAY_NOT_DISABLE; - - link_adjust.auth_delay = 2; - link_adjust.retry_limit = MAX_NUM_OF_ATTEMPTS; - - if (content_type == DRM_MODE_HDCP_CONTENT_TYPE0) { - link_adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_0; - } else if (content_type == DRM_MODE_HDCP_CONTENT_TYPE1) { - link_adjust.hdcp1.disable = 1; - link_adjust.hdcp2.force_type = MOD_HDCP_FORCE_TYPE_1; - } - link_adjust.hdcp2.use_fw_locality_check = - (dc->caps.fused_io_supported || dc->debug.hdcp_lc_force_fw_enable); - link_adjust.hdcp2.use_sw_locality_fallback = dc->debug.hdcp_lc_enable_sw_fallback; - schedule_delayed_work(&hdcp_w->property_validate_dwork, msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS)); } else { - display_adjust.disable = MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION; hdcp_w->encryption_status[conn_index] = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; cancel_delayed_work(&hdcp_w->property_validate_dwork); } @@ -336,6 +387,7 @@ static void event_property_update(struct work_struct *work) property_update_work); struct amdgpu_dm_connector *aconnector = NULL; struct drm_device *dev; + unsigned int content_protection; long ret; unsigned int conn_index; struct drm_connector *connector; @@ -375,26 +427,15 @@ static void event_property_update(struct work_struct *work) MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF; } } - if (hdcp_work->encryption_status[conn_index] != - MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF) { - if (conn_state->hdcp_content_type == - DRM_MODE_HDCP_CONTENT_TYPE0 && - hdcp_work->encryption_status[conn_index] <= - MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON) { + if (hdcp_get_content_protection_from_status(conn_state->hdcp_content_type, + hdcp_work->encryption_status[conn_index], + &content_protection)) { + if (content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED) DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_ENABLED\n"); - drm_hdcp_update_content_protection(connector, - DRM_MODE_CONTENT_PROTECTION_ENABLED); - } else if (conn_state->hdcp_content_type == - DRM_MODE_HDCP_CONTENT_TYPE1 && - hdcp_work->encryption_status[conn_index] == - MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON) { - drm_hdcp_update_content_protection(connector, - DRM_MODE_CONTENT_PROTECTION_ENABLED); - } - } else { - DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_DESIRED\n"); - drm_hdcp_update_content_protection(connector, - DRM_MODE_CONTENT_PROTECTION_DESIRED); + else + DRM_DEBUG_DRIVER("[HDCP_DM] DRM_MODE_CONTENT_PROTECTION_DESIRED\n"); + + drm_hdcp_update_content_protection(connector, content_protection); } drm_modeset_unlock(&dev->mode_config.connection_mutex); } diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h index 90b18c450ca6..3ba5823aed9f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h @@ -96,6 +96,18 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct #if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) void process_output(struct hdcp_workqueue *hdcp_work); +bool hdcp_get_content_protection_from_status( + unsigned int hdcp_content_type, + enum mod_hdcp_encryption_status encryption_status, + unsigned int *content_protection); +void hdcp_get_link_display_adjustments( + bool enable_encryption, + u8 content_type, + bool fused_io_supported, + bool hdcp_lc_force_fw_enable, + bool hdcp_lc_enable_sw_fallback, + struct mod_hdcp_link_adjustment *link_adjust, + struct mod_hdcp_display_adjustment *display_adjust); #endif #endif /* AMDGPU_DM_AMDGPU_DM_HDCP_H_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index c6f94eb71ffa..71e2627f9a9d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -48,6 +48,8 @@ #include "dm_helpers.h" #include "ddc_service_types.h" #include "clk_mgr.h" +#include "amdgpu_dm_kunit_helpers.h" +#include "amdgpu_dm_helpers.h" #define MCCS_DEST_ADDR (0x6E >> 1) #define MCCS_SRC_ADDR 0x51 @@ -88,12 +90,13 @@ union vcp_reply { unsigned char raw[11]; }; -static u32 edid_extract_panel_id(struct edid *edid) +STATIC_IFN_KUNIT u32 edid_extract_panel_id(struct edid *edid) { return (u32)edid->mfg_id[0] << 24 | (u32)edid->mfg_id[1] << 16 | (u32)EDID_PRODUCT_ID(edid); } +EXPORT_IF_KUNIT(edid_extract_panel_id); static void apply_edid_quirks(struct dc_link *link, struct edid *edid, struct dc_edid_caps *edid_caps) @@ -193,6 +196,12 @@ enum dc_edid_status dm_helpers_parse_edid_caps( __func__, connector->name, edid_caps->frl_dsc_10bpc, edid_caps->frl_dsc_12bpc, \ edid_caps->frl_dsc_all_bpp, edid_caps->frl_dsc_native_420, edid_caps->frl_dsc_max_slices, \ edid_caps->frl_dsc_max_frl_rate, edid_caps->frl_dsc_total_chunk_kbytes); + if (aconnector->hdmi_comp_auto) { + edid_caps->panel_patch.hdmi_comp_auto = true; + link->ctx->dc->debug.force_frl_max = true; + link->ctx->dc->debug.force_frl_dsc = true; + drm_dbg_driver(connector->dev, "%s: HDMI_FRL [%s] hdmi_comp_auto --> enabled\n", __func__, connector->name); + } } apply_edid_quirks(link, edid_buf, edid_caps); @@ -489,6 +498,7 @@ void dm_dtn_log_begin(struct dc_context *ctx, dm_dtn_log_append_v(ctx, log_ctx, "%s", msg); } +EXPORT_IF_KUNIT(dm_dtn_log_begin); __printf(3, 4) void dm_dtn_log_append_v(struct dc_context *ctx, @@ -551,6 +561,7 @@ void dm_dtn_log_append_v(struct dc_context *ctx, if (n > 0) log_ctx->pos += n; } +EXPORT_IF_KUNIT(dm_dtn_log_append_v); void dm_dtn_log_end(struct dc_context *ctx, struct dc_log_buffer_ctx *log_ctx) @@ -564,6 +575,7 @@ void dm_dtn_log_end(struct dc_context *ctx, dm_dtn_log_append_v(ctx, log_ctx, "%s", msg); } +EXPORT_IF_KUNIT(dm_dtn_log_end); bool dm_helpers_dp_mst_start_top_mgr( struct dc_context *ctx, @@ -598,6 +610,7 @@ bool dm_helpers_dp_mst_start_top_mgr( return true; } +EXPORT_IF_KUNIT(dm_helpers_dp_mst_start_top_mgr); bool dm_helpers_dp_mst_stop_top_mgr( struct dc_context *ctx, @@ -620,6 +633,7 @@ bool dm_helpers_dp_mst_stop_top_mgr( return false; } +EXPORT_IF_KUNIT(dm_helpers_dp_mst_stop_top_mgr); bool dm_helpers_dp_read_dpcd( struct dc_context *ctx, @@ -637,6 +651,7 @@ bool dm_helpers_dp_read_dpcd( return drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, address, data, size) == size; } +EXPORT_IF_KUNIT(dm_helpers_dp_read_dpcd); bool dm_helpers_dp_write_dpcd( struct dc_context *ctx, @@ -653,6 +668,7 @@ bool dm_helpers_dp_write_dpcd( return drm_dp_dpcd_write(&aconnector->dm_dp_aux.aux, address, (uint8_t *)data, size) > 0; } +EXPORT_IF_KUNIT(dm_helpers_dp_write_dpcd); bool dm_helpers_submit_i2c( struct dc_context *ctx, @@ -968,6 +984,7 @@ bool dm_helpers_dp_write_hblank_reduction(struct dc_context *ctx, const struct d // TODO return false; } +EXPORT_IF_KUNIT(dm_helpers_dp_write_hblank_reduction); bool dm_helpers_is_dp_sink_present(struct dc_link *link) { @@ -1085,7 +1102,7 @@ dm_helpers_read_vbios_hardcoded_edid(struct dc_link *link, struct amdgpu_dm_conn return edid; } -static uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane) +STATIC_IFN_KUNIT uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane) { uint8_t max_frl_rate; @@ -1106,6 +1123,7 @@ static uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane) return max_frl_rate; } +EXPORT_IF_KUNIT(get_max_frl_rate); static uint8_t get_dsc_max_slices(uint8_t max_slices, int clk_per_slice) { @@ -1150,6 +1168,7 @@ void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *hd } } } +EXPORT_IF_KUNIT(populate_hdmi_info_from_connector); enum dc_edid_status dm_helpers_read_local_edid( struct dc_context *ctx, @@ -1550,24 +1569,32 @@ void dm_helpers_dp_mst_update_branch_bandwidth( // TODO } -static bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id) +STATIC_IFN_KUNIT const uint32_t dm_freesync_pcon_whitelist[] = { + DP_BRANCH_DEVICE_ID_0060AD, + DP_BRANCH_DEVICE_ID_00E04C, + DP_BRANCH_DEVICE_ID_90CC24, + DP_BRANCH_DEVICE_ID_001CF8, + DP_BRANCH_DEVICE_ID_001FF2, +}; +EXPORT_IF_KUNIT(dm_freesync_pcon_whitelist); + +STATIC_IFN_KUNIT uint32_t dm_freesync_pcon_whitelist_count(void) { - bool ret_val = false; - - switch (branch_dev_id) { - case DP_BRANCH_DEVICE_ID_0060AD: - case DP_BRANCH_DEVICE_ID_00E04C: - case DP_BRANCH_DEVICE_ID_90CC24: - case DP_BRANCH_DEVICE_ID_001CF8: - case DP_BRANCH_DEVICE_ID_001FF2: - ret_val = true; - break; - default: - break; - } - - return ret_val; + return ARRAY_SIZE(dm_freesync_pcon_whitelist); } +EXPORT_IF_KUNIT(dm_freesync_pcon_whitelist_count); + +STATIC_IFN_KUNIT bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id) +{ + u32 i; + + for (i = 0; i < dm_freesync_pcon_whitelist_count(); i++) + if (dm_freesync_pcon_whitelist[i] == branch_dev_id) + return true; + + return false; +} +EXPORT_IF_KUNIT(dm_is_freesync_pcon_whitelist); enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link) { @@ -1587,18 +1614,21 @@ enum adaptive_sync_type dm_get_adaptive_sync_support_type(struct dc_link *link) return as_type; } +EXPORT_IF_KUNIT(dm_get_adaptive_sync_support_type); bool dm_helpers_is_fullscreen(struct dc_context *ctx, struct dc_stream_state *stream) { // TODO return false; } +EXPORT_IF_KUNIT(dm_helpers_is_fullscreen); bool dm_helpers_is_hdr_on(struct dc_context *ctx, struct dc_stream_state *stream) { // TODO return false; } +EXPORT_IF_KUNIT(dm_helpers_is_hdr_on); static int mccs_operation_vcp_request(unsigned int vcp_code, struct dc_link *link, union vcp_reply *reply) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h new file mode 100644 index 000000000000..2ac9762895ec --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#ifndef __AMDGPU_DM_HELPERS_H__ +#define __AMDGPU_DM_HELPERS_H__ + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +#include + +/* Exported for KUnit testing */ +u32 edid_extract_panel_id(struct edid *edid); +uint8_t get_max_frl_rate(uint8_t max_lanes, uint8_t max_rate_per_lane); +bool dm_is_freesync_pcon_whitelist(const uint32_t branch_dev_id); +extern const uint32_t dm_freesync_pcon_whitelist[]; +uint32_t dm_freesync_pcon_whitelist_count(void); +#endif /* CONFIG_DRM_AMD_DC_KUNIT_TEST */ + +#endif /* __AMDGPU_DM_HELPERS_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c index e49803a90eda..551901c7598a 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c @@ -26,10 +26,25 @@ #include "dm_services_types.h" #include "dc.h" +#include "dc/dc_dmub_srv.h" +#include "dc/dc_stat.h" #include "amdgpu.h" +#include "amdgpu_display.h" #include "amdgpu_dm.h" #include "amdgpu_dm_irq.h" +#include "amdgpu_dm_kunit_helpers.h" +#include "amdgpu_dm_crtc.h" +#include "amdgpu_dm_hdcp.h" +#include "amdgpu_dm_mst_types.h" +#include "amdgpu_dm_dmub.h" +#include "amdgpu_dm_trace.h" +#include "link/protocols/link_dpcd.h" +#include "link_service_types.h" +#include "ivsrcid/ivsrcid_vislands30.h" +#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h" +#include "modules/inc/mod_freesync.h" +#include /** * DOC: overview @@ -55,7 +70,8 @@ * are all set to the DM generic handler amdgpu_dm_irq_handler(), which looks up * DM's IRQ tables. However, in order for base driver to recognize this hook, DM * still needs to register the IRQ with the base driver. See - * dce110_register_irq_handlers() and dcn10_register_irq_handlers(). + * amdgpu_dm_dce110_register_irq_handlers() and + * amdgpu_dm_dcn10_register_irq_handlers(). * * To expose DC's hardware interrupt toggle to the base driver, DM implements * &amdgpu_irq_src_funcs.set hooks. Base driver calls it through @@ -172,7 +188,7 @@ static struct list_head *remove_irq_handler(struct amdgpu_device *adev, DM_IRQ_TABLE_UNLOCK(adev, irq_table_flags); - if (handler_removed == false) { + if (!handler_removed) { /* Not necessarily an error - caller may not * know the context. */ @@ -310,7 +326,7 @@ void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev, unsigned long irq_table_flags; enum dc_irq_source irq_source; - if (false == validate_irq_registration_params(int_params, ih)) + if (!validate_irq_registration_params(int_params, ih)) return DAL_INVALID_IRQ_HANDLER_IDX; handler_data = kzalloc_obj(*handler_data); @@ -357,6 +373,7 @@ void *amdgpu_dm_irq_register_interrupt(struct amdgpu_device *adev, return handler_data; } +EXPORT_IF_KUNIT(amdgpu_dm_irq_register_interrupt); /** * amdgpu_dm_irq_unregister_interrupt() - Remove a handler from the DM IRQ table @@ -375,7 +392,7 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev, struct dc_interrupt_params int_params; int i; - if (false == validate_irq_unregistration_params(irq_source, ih)) + if (!validate_irq_unregistration_params(irq_source, ih)) return; memset(&int_params, 0, sizeof(int_params)); @@ -401,6 +418,7 @@ void amdgpu_dm_irq_unregister_interrupt(struct amdgpu_device *adev, ih, irq_source); } } +EXPORT_IF_KUNIT(amdgpu_dm_irq_unregister_interrupt); /** * amdgpu_dm_irq_init() - Initialize DM IRQ management @@ -435,6 +453,7 @@ int amdgpu_dm_irq_init(struct amdgpu_device *adev) return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_irq_init); /** * amdgpu_dm_irq_fini() - Tear down DM IRQ management @@ -473,6 +492,7 @@ void amdgpu_dm_irq_fini(struct amdgpu_device *adev) /* Deallocate handlers from the table. */ unregister_all_irq_handlers(adev); } +EXPORT_IF_KUNIT(amdgpu_dm_irq_fini); void amdgpu_dm_irq_suspend(struct amdgpu_device *adev) { @@ -675,7 +695,7 @@ static int amdgpu_dm_irq_handler(struct amdgpu_device *adev, return 0; } -static enum dc_irq_source amdgpu_dm_hpd_to_dal_irq_source(unsigned int type) +STATIC_IFN_KUNIT enum dc_irq_source amdgpu_dm_hpd_to_dal_irq_source(unsigned int type) { switch (type) { case AMDGPU_HPD_1: @@ -694,6 +714,7 @@ static enum dc_irq_source amdgpu_dm_hpd_to_dal_irq_source(unsigned int type) return DC_IRQ_SOURCE_INVALID; } } +EXPORT_IF_KUNIT(amdgpu_dm_hpd_to_dal_irq_source); static int amdgpu_dm_set_hpd_irq_state(struct amdgpu_device *adev, struct amdgpu_irq_src *source, @@ -1020,3 +1041,1520 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev) if (dev->mode_config.poll_enabled) drm_kms_helper_poll_fini(dev); } + +/* ========== HPD handling ========== */ +static void force_connector_state( + struct amdgpu_dm_connector *aconnector, + enum drm_connector_force force_state) +{ + struct drm_connector *connector = &aconnector->base; + + mutex_lock(&connector->dev->mode_config.mutex); + aconnector->base.force = force_state; + mutex_unlock(&connector->dev->mode_config.mutex); + + mutex_lock(&aconnector->hpd_lock); + drm_kms_helper_connector_hotplug_event(connector); + mutex_unlock(&aconnector->hpd_lock); +} + +static void dm_handle_hpd_rx_offload_work(struct work_struct *work) +{ + struct hpd_rx_irq_offload_work *offload_work; + struct amdgpu_dm_connector *aconnector; + struct dc_link *dc_link; + struct amdgpu_device *adev; + enum dc_connection_type new_connection_type = dc_connection_none; + unsigned long flags; + union test_response test_response; + + memset(&test_response, 0, sizeof(test_response)); + + offload_work = container_of(work, struct hpd_rx_irq_offload_work, work); + aconnector = offload_work->offload_wq->aconnector; + adev = offload_work->adev; + + if (!aconnector) { + drm_err(adev_to_drm(adev), "Can't retrieve aconnector in hpd_rx_irq_offload_work"); + goto skip; + } + + dc_link = aconnector->dc_link; + + mutex_lock(&aconnector->hpd_lock); + if (!dc_link_detect_connection_type(dc_link, &new_connection_type)) + drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); + mutex_unlock(&aconnector->hpd_lock); + + if (new_connection_type == dc_connection_none) + goto skip; + + if (amdgpu_in_reset(adev)) + goto skip; + + if (offload_work->data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY || + offload_work->data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) { + dm_handle_mst_sideband_msg_ready_event(&aconnector->mst_mgr, DOWN_OR_UP_MSG_RDY_EVENT); + spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags); + offload_work->offload_wq->is_handling_mst_msg_rdy_event = false; + spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags); + goto skip; + } + + mutex_lock(&adev->dm.dc_lock); + if (offload_work->data.bytes.device_service_irq.bits.AUTOMATED_TEST) { + dc_link_dp_handle_automated_test(dc_link); + + if (aconnector->timing_changed) { + /* force connector disconnect and reconnect */ + force_connector_state(aconnector, DRM_FORCE_OFF); + msleep(100); + force_connector_state(aconnector, DRM_FORCE_UNSPECIFIED); + } + + test_response.bits.ACK = 1; + + core_link_write_dpcd( + dc_link, + DP_TEST_RESPONSE, + &test_response.raw, + sizeof(test_response)); + } else if ((dc_link->connector_signal != SIGNAL_TYPE_EDP) && + dc_link_check_link_loss_status(dc_link, &offload_work->data) && + dc_link_dp_allow_hpd_rx_irq(dc_link)) { + /* offload_work->data is from handle_hpd_rx_irq-> + * schedule_hpd_rx_offload_work.this is defer handle + * for hpd short pulse. upon here, link status may be + * changed, need get latest link status from dpcd + * registers. if link status is good, skip run link + * training again. + */ + union hpd_irq_data irq_data; + + memset(&irq_data, 0, sizeof(irq_data)); + + /* before dc_link_dp_handle_link_loss, allow new link lost handle + * request be added to work queue if link lost at end of dc_link_ + * dp_handle_link_loss + */ + spin_lock_irqsave(&offload_work->offload_wq->offload_lock, flags); + offload_work->offload_wq->is_handling_link_loss = false; + spin_unlock_irqrestore(&offload_work->offload_wq->offload_lock, flags); + + if ((dc_link_dp_read_hpd_rx_irq_data(dc_link, &irq_data) == DC_OK) && + dc_link_check_link_loss_status(dc_link, &irq_data)) + dc_link_dp_handle_link_loss(dc_link); + } + mutex_unlock(&adev->dm.dc_lock); + +skip: + kfree(offload_work); + +} + +struct hpd_rx_irq_offload_work_queue *amdgpu_dm_hpd_rx_irq_create_workqueue(struct amdgpu_device *adev) +{ + struct dc *dc = adev->dm.dc; + int max_caps = dc->caps.max_links; + int i = 0; + struct hpd_rx_irq_offload_work_queue *hpd_rx_offload_wq = NULL; + + hpd_rx_offload_wq = kzalloc_objs(*hpd_rx_offload_wq, max_caps); + + if (!hpd_rx_offload_wq) + return NULL; + + + for (i = 0; i < max_caps; i++) { + hpd_rx_offload_wq[i].wq = + create_singlethread_workqueue("amdgpu_dm_hpd_rx_offload_wq"); + + if (hpd_rx_offload_wq[i].wq == NULL) { + drm_err(adev_to_drm(adev), "create amdgpu_dm_hpd_rx_offload_wq fail!"); + goto out_err; + } + + spin_lock_init(&hpd_rx_offload_wq[i].offload_lock); + } + + return hpd_rx_offload_wq; + +out_err: + for (i = 0; i < max_caps; i++) { + if (hpd_rx_offload_wq[i].wq) + destroy_workqueue(hpd_rx_offload_wq[i].wq); + } + kfree(hpd_rx_offload_wq); + return NULL; +} + +void amdgpu_dm_hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm) +{ + int i; + + if (dm->hpd_rx_offload_wq) { + for (i = 0; i < dm->dc->caps.max_links; i++) + flush_workqueue(dm->hpd_rx_offload_wq[i].wq); + } +} + +STATIC_IFN_KUNIT bool are_sinks_equal(const struct dc_sink *sink1, const struct dc_sink *sink2) +{ + if (!sink1 || !sink2) + return false; + if (sink1->sink_signal != sink2->sink_signal) + return false; + + if (sink1->dc_edid.length != sink2->dc_edid.length) + return false; + + if (memcmp(sink1->dc_edid.raw_edid, sink2->dc_edid.raw_edid, + sink1->dc_edid.length) != 0) + return false; + return true; +} +EXPORT_IF_KUNIT(are_sinks_equal); + + +/** + * DOC: amdgpu_dm_hdmi_hpd_debounce_work + * + * HDMI HPD debounce delay in milliseconds. When an HDMI display toggles HPD + * (such as during power save transitions), this delay determines how long to + * wait before processing the HPD event. This allows distinguishing between a + * physical unplug (>hdmi_hpd_debounce_delay) + * and a spontaneous RX HPD toggle (base; + struct drm_device *dev = connector->dev; + struct amdgpu_device *adev = drm_to_adev(dev); + struct dc *dc = aconnector->dc_link->ctx->dc; + bool fake_reconnect = false; + bool reallow_idle = false; + bool ret = false; + + guard(mutex)(&aconnector->hpd_lock); + + /* Re-detect the display */ + scoped_guard(mutex, &adev->dm.dc_lock) { + if (dc->caps.ips_support && dc->ctx->dmub_srv->idle_allowed) { + dc_allow_idle_optimizations(dc, false); + reallow_idle = true; + } + ret = dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD); + } + + if (ret) { + /* Apply workaround delay for certain panels */ + amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink); + /* Compare sinks to determine if this was a spontaneous HPD toggle */ + if (are_sinks_equal(aconnector->dc_link->local_sink, aconnector->hdmi_prev_sink)) { + /* + * Sinks match - this was a spontaneous HDMI HPD toggle. + */ + drm_dbg_kms(dev, "HDMI HPD: Sink unchanged after debounce, internal re-enable\n"); + fake_reconnect = true; + } + + /* Update connector state */ + amdgpu_dm_update_connector_after_detect(aconnector); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + /* Only notify OS if sink actually changed */ + if (!fake_reconnect && aconnector->base.force == DRM_FORCE_UNSPECIFIED) + drm_kms_helper_hotplug_event(dev); + } + + /* Release the cached sink reference */ + if (aconnector->hdmi_prev_sink) { + dc_sink_release(aconnector->hdmi_prev_sink); + aconnector->hdmi_prev_sink = NULL; + } + + scoped_guard(mutex, &adev->dm.dc_lock) { + if (reallow_idle && dc->caps.ips_support) + dc_allow_idle_optimizations(dc, true); + } +} + +static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector, + enum dc_detect_reason reason) +{ + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + enum dc_connection_type new_connection_type = dc_connection_none; + struct amdgpu_device *adev = drm_to_adev(dev); + struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state); + struct dc *dc = aconnector->dc_link->ctx->dc; + bool ret = false; + bool debounce_required = false; + + if (adev->dm.disable_hpd_irq) + return; + + /* + * In case of failure or MST no need to update connector status or notify the OS + * since (for MST case) MST does this in its own context. + */ + guard(mutex)(&aconnector->hpd_lock); + + if (adev->dm.hdcp_workqueue) { + hdcp_reset_display(adev->dm.hdcp_workqueue, aconnector->dc_link->link_index); + dm_con_state->update_hdcp = true; + } + if (aconnector->fake_enable) + aconnector->fake_enable = false; + + aconnector->timing_changed = false; + + if (!dc_link_detect_connection_type(aconnector->dc_link, &new_connection_type)) + drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); + + /* + * Check for HDMI disconnect with debounce enabled. + */ + debounce_required = (aconnector->hdmi_hpd_debounce_delay_ms > 0 && + dc_is_hdmi_signal(aconnector->dc_link->connector_signal) && + new_connection_type == dc_connection_none && + aconnector->dc_link->local_sink != NULL); + + if (aconnector->base.force && new_connection_type == dc_connection_none) { + amdgpu_dm_emulated_link_detect(aconnector->dc_link); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + if (aconnector->base.force == DRM_FORCE_UNSPECIFIED || + reason == DETECT_REASON_HPDRX) + drm_kms_helper_connector_hotplug_event(connector); + } else if (debounce_required) { + /* + * HDMI disconnect detected - schedule delayed work instead of + * processing immediately. This allows us to coalesce spurious + * HDMI signals from physical unplugs. + */ + drm_dbg_kms(dev, "HDMI HPD: Disconnect detected, scheduling debounce work (%u ms)\n", + aconnector->hdmi_hpd_debounce_delay_ms); + + /* Cache the current sink for later comparison */ + if (aconnector->hdmi_prev_sink) + dc_sink_release(aconnector->hdmi_prev_sink); + aconnector->hdmi_prev_sink = aconnector->dc_link->local_sink; + if (aconnector->hdmi_prev_sink) + dc_sink_retain(aconnector->hdmi_prev_sink); + + /* Schedule delayed detection. */ + if (mod_delayed_work(system_percpu_wq, + &aconnector->hdmi_hpd_debounce_work, + msecs_to_jiffies(aconnector->hdmi_hpd_debounce_delay_ms))) + drm_dbg_kms(dev, "HDMI HPD: Re-scheduled debounce work\n"); + + } else { + + /* If the aconnector->hdmi_hpd_debounce_work is scheduled, exit early */ + if (delayed_work_pending(&aconnector->hdmi_hpd_debounce_work)) + return; + + scoped_guard(mutex, &adev->dm.dc_lock) { + dc_exit_ips_for_hw_access(dc); + ret = dc_link_detect(aconnector->dc_link, reason); + } + if (ret) { + /* w/a delay for certain panels */ + amdgpu_dm_apply_delay_after_dpcd_poweroff(adev, aconnector->dc_sink); + amdgpu_dm_update_connector_after_detect(aconnector); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + if (aconnector->base.force == DRM_FORCE_UNSPECIFIED || + reason == DETECT_REASON_HPDRX) + drm_kms_helper_connector_hotplug_event(connector); + } + } +} + +static void handle_hpd_irq(void *param) +{ + struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param; + + handle_hpd_irq_helper(aconnector, DETECT_REASON_HPD); + +} + +static void schedule_hpd_rx_offload_work(struct amdgpu_device *adev, struct hpd_rx_irq_offload_work_queue *offload_wq, + union hpd_irq_data hpd_irq_data) +{ + struct hpd_rx_irq_offload_work *offload_work = kzalloc_obj(*offload_work); + + if (!offload_work) { + drm_err(adev_to_drm(adev), "Failed to allocate hpd_rx_irq_offload_work.\n"); + return; + } + + INIT_WORK(&offload_work->work, dm_handle_hpd_rx_offload_work); + offload_work->data = hpd_irq_data; + offload_work->offload_wq = offload_wq; + offload_work->adev = adev; + + queue_work(offload_wq->wq, &offload_work->work); + drm_dbg_kms(adev_to_drm(adev), "queue work to handle hpd_rx offload work"); +} + +static void handle_hpd_rx_irq(void *param) +{ + struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param; + struct drm_connector *connector = &aconnector->base; + struct drm_device *dev = connector->dev; + struct dc_link *dc_link = aconnector->dc_link; + bool is_mst_root_connector = aconnector->mst_mgr.mst_state; + bool result = false; + enum dc_connection_type new_connection_type = dc_connection_none; + struct amdgpu_device *adev = drm_to_adev(dev); + union hpd_irq_data hpd_irq_data; + bool link_loss = false; + bool has_left_work = false; + int idx = dc_link->link_index; + struct hpd_rx_irq_offload_work_queue *offload_wq = &adev->dm.hpd_rx_offload_wq[idx]; + struct dc *dc = aconnector->dc_link->ctx->dc; + + memset(&hpd_irq_data, 0, sizeof(hpd_irq_data)); + + if (adev->dm.disable_hpd_irq) + return; + + /* + * TODO:Temporary add mutex to protect hpd interrupt not have a gpio + * conflict, after implement i2c helper, this mutex should be + * retired. + */ + mutex_lock(&aconnector->hpd_lock); + + result = dc_link_handle_hpd_rx_irq(dc_link, &hpd_irq_data, + &link_loss, true, &has_left_work); + + if (!has_left_work) + goto out; + + if (hpd_irq_data.bytes.device_service_irq.bits.AUTOMATED_TEST) { + schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data); + goto out; + } + + if (dc_link_dp_allow_hpd_rx_irq(dc_link)) { + if (hpd_irq_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY || + hpd_irq_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) { + bool skip = false; + + /* + * DOWN_REP_MSG_RDY is also handled by polling method + * mgr->cbs->poll_hpd_irq() + */ + spin_lock(&offload_wq->offload_lock); + skip = offload_wq->is_handling_mst_msg_rdy_event; + + if (!skip) + offload_wq->is_handling_mst_msg_rdy_event = true; + + spin_unlock(&offload_wq->offload_lock); + + if (!skip) + schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data); + + goto out; + } + + if (link_loss) { + bool skip = false; + + spin_lock(&offload_wq->offload_lock); + skip = offload_wq->is_handling_link_loss; + + if (!skip) + offload_wq->is_handling_link_loss = true; + + spin_unlock(&offload_wq->offload_lock); + + if (!skip) + schedule_hpd_rx_offload_work(adev, offload_wq, hpd_irq_data); + + goto out; + } + } + +out: + if (result && !is_mst_root_connector) { + /* Downstream Port status changed. */ + if (!dc_link_detect_connection_type(dc_link, &new_connection_type)) + drm_err(adev_to_drm(adev), "KMS: Failed to detect connector\n"); + + if (aconnector->base.force && new_connection_type == dc_connection_none) { + amdgpu_dm_emulated_link_detect(dc_link); + + if (aconnector->fake_enable) + aconnector->fake_enable = false; + + amdgpu_dm_update_connector_after_detect(aconnector); + + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + drm_kms_helper_connector_hotplug_event(connector); + } else { + bool ret = false; + + mutex_lock(&adev->dm.dc_lock); + dc_exit_ips_for_hw_access(dc); + ret = dc_link_detect(dc_link, DETECT_REASON_HPDRX); + mutex_unlock(&adev->dm.dc_lock); + + if (ret) { + if (aconnector->fake_enable) + aconnector->fake_enable = false; + + amdgpu_dm_update_connector_after_detect(aconnector); + + drm_modeset_lock_all(dev); + dm_restore_drm_connector_state(dev, connector); + drm_modeset_unlock_all(dev); + + drm_kms_helper_connector_hotplug_event(connector); + } + } + } + if (hpd_irq_data.bytes.device_service_irq.bits.CP_IRQ) { + if (adev->dm.hdcp_workqueue) + hdcp_handle_cpirq(adev->dm.hdcp_workqueue, aconnector->base.index); + } + + if (dc_link->type != dc_connection_mst_branch) + drm_dp_cec_irq(&aconnector->dm_dp_aux.aux); + + mutex_unlock(&aconnector->hpd_lock); +} + +/** + * dmub_hpd_callback - DMUB HPD interrupt processing callback. + * @adev: amdgpu_device pointer + * @notify: dmub notification structure + * + * Dmub Hpd interrupt processing callback. Gets displayindex through the + * ink index and calls helper to do the processing. + */ +static void dmub_hpd_callback(struct amdgpu_device *adev, + struct dmub_notification *notify) +{ + struct amdgpu_dm_connector *aconnector; + struct amdgpu_dm_connector *hpd_aconnector = NULL; + struct drm_connector *connector; + struct drm_connector_list_iter iter; + struct dc_link *link; + u8 link_index = 0; + struct drm_device *dev; + + if (adev == NULL) + return; + + if (notify == NULL) { + drm_err(adev_to_drm(adev), "DMUB HPD callback notification was NULL"); + return; + } + + if (notify->link_index > adev->dm.dc->link_count) { + drm_err(adev_to_drm(adev), "DMUB HPD index (%u)is abnormal", notify->link_index); + return; + } + + /* Skip DMUB HPD IRQ in suspend/resume. We will probe them later. */ + if (notify->type == DMUB_NOTIFICATION_HPD && adev->in_suspend) { + drm_info(adev_to_drm(adev), "Skip DMUB HPD IRQ callback in suspend/resume\n"); + return; + } + + link_index = notify->link_index; + link = adev->dm.dc->links[link_index]; + dev = adev->dm.ddev; + + drm_connector_list_iter_begin(dev, &iter); + drm_for_each_connector_iter(connector, &iter) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + if (link && aconnector->dc_link == link) { + if (notify->type == DMUB_NOTIFICATION_HPD) + drm_info(adev_to_drm(adev), "DMUB HPD IRQ callback: link_index=%u\n", link_index); + else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ) + drm_info(adev_to_drm(adev), "DMUB HPD RX IRQ callback: link_index=%u\n", link_index); + else + drm_warn(adev_to_drm(adev), "DMUB Unknown HPD callback type %d, link_index=%u\n", + notify->type, link_index); + + hpd_aconnector = aconnector; + break; + } + } + drm_connector_list_iter_end(&iter); + + if (hpd_aconnector) { + if (notify->type == DMUB_NOTIFICATION_HPD) { + if (hpd_aconnector->dc_link->hpd_status == (notify->hpd_status == DP_HPD_PLUG)) + drm_warn(adev_to_drm(adev), "DMUB reported hpd status unchanged. link_index=%u\n", link_index); + handle_hpd_irq_helper(hpd_aconnector, DETECT_REASON_HPD); + } else if (notify->type == DMUB_NOTIFICATION_HPD_IRQ) { + handle_hpd_rx_irq(hpd_aconnector); + } + } +} + +/** + * dmub_hpd_sense_callback - DMUB HPD sense processing callback. + * @adev: amdgpu_device pointer + * @notify: dmub notification structure + * + * HPD sense changes can occur during low power states and need to be + * notified from firmware to driver. + */ +static void dmub_hpd_sense_callback(struct amdgpu_device *adev, + struct dmub_notification *notify) +{ + drm_dbg_driver(adev_to_drm(adev), "DMUB HPD SENSE callback.\n"); +} + +int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev) +{ + struct drm_device *dev = adev_to_drm(adev); + struct drm_connector *connector; + struct amdgpu_dm_connector *aconnector; + const struct dc_link *dc_link; + struct dc_interrupt_params int_params = {0}; + + int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; + int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; + + if (dc_is_dmub_outbox_supported(adev->dm.dc)) { + if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD, + dmub_hpd_callback, true)) { + drm_err(adev_to_drm(adev), "fail to register dmub hpd callback"); + return -EINVAL; + } + + if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_IRQ, + dmub_hpd_callback, true)) { + drm_err(adev_to_drm(adev), "fail to register dmub hpd callback"); + return -EINVAL; + } + + if (!dm_register_dmub_notify_callback(adev, DMUB_NOTIFICATION_HPD_SENSE_NOTIFY, + dmub_hpd_sense_callback, true)) { + drm_err(adev_to_drm(adev), "fail to register dmub hpd sense callback"); + return -EINVAL; + } + } + + list_for_each_entry(connector, + &dev->mode_config.connector_list, head) { + + if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK) + continue; + + aconnector = to_amdgpu_dm_connector(connector); + dc_link = aconnector->dc_link; + + if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) { + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = dc_link->irq_source_hpd; + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_HPD1 || + int_params.irq_source > DC_IRQ_SOURCE_HPD6) { + drm_err(adev_to_drm(adev), "Failed to register hpd irq!\n"); + return -EINVAL; + } + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + handle_hpd_irq, (void *) aconnector)) + return -ENOMEM; + } + + if (dc_link->irq_source_hpd_rx != DC_IRQ_SOURCE_INVALID) { + + /* Also register for DP short pulse (hpd_rx). */ + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = dc_link->irq_source_hpd_rx; + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_HPD1RX || + int_params.irq_source > DC_IRQ_SOURCE_HPD6RX) { + drm_err(adev_to_drm(adev), "Failed to register hpd rx irq!\n"); + return -EINVAL; + } + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + handle_hpd_rx_irq, (void *) aconnector)) + return -ENOMEM; + } + } + return 0; +} + +/* ========== IRQ handlers ========== */ +struct amdgpu_crtc * +amdgpu_dm_get_crtc_by_otg_inst(struct amdgpu_device *adev, + int otg_inst) +{ + struct drm_device *dev = adev_to_drm(adev); + struct drm_crtc *crtc; + struct amdgpu_crtc *amdgpu_crtc; + + if (WARN_ON(otg_inst == -1)) + return adev->mode_info.crtcs[0]; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + amdgpu_crtc = to_amdgpu_crtc(crtc); + + if (amdgpu_crtc->otg_inst == otg_inst) + return amdgpu_crtc; + } + + return NULL; +} +EXPORT_IF_KUNIT(amdgpu_dm_get_crtc_by_otg_inst); + +/** + * dm_pflip_high_irq() - Handle pageflip interrupt + * @interrupt_params: ignored + * + * Handles the pageflip interrupt by notifying all interested parties + * that the pageflip has been completed. + */ +static void dm_pflip_high_irq(void *interrupt_params) +{ + struct amdgpu_crtc *amdgpu_crtc; + struct common_irq_params *irq_params = interrupt_params; + struct amdgpu_device *adev = irq_params->adev; + struct drm_device *dev = adev_to_drm(adev); + unsigned long flags; + struct drm_pending_vblank_event *e; + u32 vpos, hpos, v_blank_start, v_blank_end; + bool vrr_active; + + amdgpu_crtc = amdgpu_dm_get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP); + + /* IRQ could occur when in initial stage */ + /* TODO work and BO cleanup */ + if (amdgpu_crtc == NULL) { + drm_dbg_state(dev, "CRTC is null, returning.\n"); + return; + } + + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); + + if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED) { + drm_dbg_state(dev, + "amdgpu_crtc->pflip_status = %d != AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p]\n", + amdgpu_crtc->pflip_status, AMDGPU_FLIP_SUBMITTED, + amdgpu_crtc->crtc_id, amdgpu_crtc); + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); + return; + } + + /* page flip completed. */ + e = amdgpu_crtc->event; + amdgpu_crtc->event = NULL; + + WARN_ON(!e); + + vrr_active = amdgpu_dm_crtc_vrr_active_irq(amdgpu_crtc); + + /* Fixed refresh rate, or VRR scanout position outside front-porch? */ + if (!vrr_active || + !dc_stream_get_scanoutpos(amdgpu_crtc->dm_irq_params.stream, &v_blank_start, + &v_blank_end, &hpos, &vpos) || + (vpos < v_blank_start)) { + /* Update to correct count and vblank timestamp if racing with + * vblank irq. This also updates to the correct vblank timestamp + * even in VRR mode, as scanout is past the front-porch atm. + */ + drm_crtc_accurate_vblank_count(&amdgpu_crtc->base); + + /* Wake up userspace by sending the pageflip event with proper + * count and timestamp of vblank of flip completion. + */ + if (e) { + drm_crtc_send_vblank_event(&amdgpu_crtc->base, e); + + /* Event sent, so done with vblank for this flip */ + drm_crtc_vblank_put(&amdgpu_crtc->base); + } + } else if (e) { + /* VRR active and inside front-porch: vblank count and + * timestamp for pageflip event will only be up to date after + * drm_crtc_handle_vblank() has been executed from late vblank + * irq handler after start of back-porch (vline 0). We queue the + * pageflip event for send-out by drm_crtc_handle_vblank() with + * updated timestamp and count, once it runs after us. + * + * We need to open-code this instead of using the helper + * drm_crtc_arm_vblank_event(), as that helper would + * call drm_crtc_accurate_vblank_count(), which we must + * not call in VRR mode while we are in front-porch! + */ + + /* sequence will be replaced by real count during send-out. */ + e->sequence = drm_crtc_vblank_count(&amdgpu_crtc->base); + e->pipe = amdgpu_crtc->crtc_id; + + list_add_tail(&e->base.link, &adev_to_drm(adev)->vblank_event_list); + e = NULL; + } + + /* Keep track of vblank of this flip for flip throttling. We use the + * cooked hw counter, as that one incremented at start of this vblank + * of pageflip completion, so last_flip_vblank is the forbidden count + * for queueing new pageflips if vsync + VRR is enabled. + */ + amdgpu_crtc->dm_irq_params.last_flip_vblank = + amdgpu_get_vblank_counter_kms(&amdgpu_crtc->base); + + amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE; + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); + + drm_dbg_state(dev, + "crtc:%d[%p], pflip_stat:AMDGPU_FLIP_NONE, vrr[%d]-fp %d\n", + amdgpu_crtc->crtc_id, amdgpu_crtc, vrr_active, (int)!e); +} + +static void dm_handle_vmin_vmax_update(struct work_struct *offload_work) +{ + struct vupdate_offload_work *work = container_of(offload_work, struct vupdate_offload_work, work); + struct amdgpu_device *adev = work->adev; + struct dc_stream_state *stream = work->stream; + struct dc_crtc_timing_adjust *adjust = work->adjust; + + mutex_lock(&adev->dm.dc_lock); + dc_stream_adjust_vmin_vmax(adev->dm.dc, stream, adjust); + mutex_unlock(&adev->dm.dc_lock); + + dc_stream_release(stream); + kfree(work->adjust); + kfree(work); +} + +static void schedule_dc_vmin_vmax(struct amdgpu_device *adev, + struct dc_stream_state *stream, + struct dc_crtc_timing_adjust *adjust) +{ + struct vupdate_offload_work *offload_work = kzalloc_obj(*offload_work, + GFP_NOWAIT); + if (!offload_work) { + drm_dbg_driver(adev_to_drm(adev), "Failed to allocate vupdate_offload_work\n"); + return; + } + + struct dc_crtc_timing_adjust *adjust_copy = kzalloc_obj(*adjust_copy, + GFP_NOWAIT); + if (!adjust_copy) { + drm_dbg_driver(adev_to_drm(adev), "Failed to allocate adjust_copy\n"); + kfree(offload_work); + return; + } + + dc_stream_retain(stream); + memcpy(adjust_copy, adjust, sizeof(*adjust_copy)); + + INIT_WORK(&offload_work->work, dm_handle_vmin_vmax_update); + offload_work->adev = adev; + offload_work->stream = stream; + offload_work->adjust = adjust_copy; + + queue_work(system_percpu_wq, &offload_work->work); +} + +static void dm_vupdate_high_irq(void *interrupt_params) +{ + struct common_irq_params *irq_params = interrupt_params; + struct amdgpu_device *adev = irq_params->adev; + struct amdgpu_crtc *acrtc; + struct drm_device *drm_dev; + struct drm_vblank_crtc *vblank; + ktime_t frame_duration_ns, previous_timestamp; + unsigned long flags; + int vrr_active; + + acrtc = amdgpu_dm_get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VUPDATE); + + if (acrtc) { + vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); + drm_dev = acrtc->base.dev; + vblank = drm_crtc_vblank_crtc(&acrtc->base); + previous_timestamp = atomic64_read(&irq_params->previous_timestamp); + frame_duration_ns = vblank->time - previous_timestamp; + + if (frame_duration_ns > 0) { + trace_amdgpu_refresh_rate_track(acrtc->base.index, + frame_duration_ns, + ktime_divns(NSEC_PER_SEC, frame_duration_ns)); + atomic64_set(&irq_params->previous_timestamp, vblank->time); + } + + drm_dbg_vbl(drm_dev, + "crtc:%d, vupdate-vrr:%d\n", acrtc->crtc_id, + vrr_active); + + /* Core vblank handling is done here after end of front-porch in + * vrr mode, as vblank timestamping will give valid results + * while now done after front-porch. This will also deliver + * page-flip completion events that have been queued to us + * if a pageflip happened inside front-porch. + */ + if (vrr_active && acrtc->dm_irq_params.stream) { + bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; + bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; + bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state + == VRR_STATE_ACTIVE_VARIABLE; + + amdgpu_dm_crtc_handle_vblank(acrtc); + + /* BTR processing for pre-DCE12 ASICs */ + if (adev->family < AMDGPU_FAMILY_AI) { + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); + mod_freesync_handle_v_update( + adev->dm.freesync_module, + acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params); + + if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { + schedule_dc_vmin_vmax(adev, + acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params.adjust); + } + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); + } + } + } +} + +/** + * dm_crtc_high_irq() - Handles CRTC interrupt + * @interrupt_params: used for determining the CRTC instance + * + * Handles the CRTC/VSYNC interrupt by notfying DRM's VBLANK + * event handler. + */ +static void dm_crtc_high_irq(void *interrupt_params) +{ + struct common_irq_params *irq_params = interrupt_params; + struct amdgpu_device *adev = irq_params->adev; + struct amdgpu_crtc *acrtc; + unsigned long flags; + int vrr_active; + + acrtc = amdgpu_dm_get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); + if (!acrtc) + return; + + if (acrtc->wb_conn && acrtc->wb_pending) { + struct dc_stream_state *stream = acrtc->dm_irq_params.stream; + unsigned int v_total, refresh_hz; + + v_total = stream->adjust.v_total_max ? + stream->adjust.v_total_max : stream->timing.v_total; + refresh_hz = div_u64((uint64_t) stream->timing.pix_clk_100hz * + 100LL, (v_total * stream->timing.h_total)); + mdelay(1000 / refresh_hz); + + /* + * Completion (signalling the out fence and releasing the vblank + * reference taken in dm_set_writeback()) is handled by the shared + * helper, which is also used by the teardown path. + */ + if (amdgpu_dm_crtc_complete_writeback(acrtc)) + dc_stream_fc_disable_writeback(adev->dm.dc, + acrtc->dm_irq_params.stream, 0); + } + + vrr_active = amdgpu_dm_crtc_vrr_active_irq(acrtc); + + drm_dbg_vbl(adev_to_drm(adev), + "crtc:%d, vupdate-vrr:%d, planes:%d\n", acrtc->crtc_id, + vrr_active, acrtc->dm_irq_params.active_planes); + + /** + * Core vblank handling at start of front-porch is only possible + * in non-vrr mode, as only there vblank timestamping will give + * valid results while done in front-porch. Otherwise defer it + * to dm_vupdate_high_irq after end of front-porch. + */ + if (!vrr_active) + amdgpu_dm_crtc_handle_vblank(acrtc); + + /** + * Following stuff must happen at start of vblank, for crc + * computation and below-the-range btr support in vrr mode. + */ + amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); + + /* BTR updates need to happen before VUPDATE on Vega and above. */ + if (adev->family < AMDGPU_FAMILY_AI) + return; + + spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags); + + if (acrtc->dm_irq_params.stream && + acrtc->dm_irq_params.vrr_params.supported) { + bool replay_en = acrtc->dm_irq_params.stream->link->replay_settings.replay_feature_enabled; + bool psr_en = acrtc->dm_irq_params.stream->link->psr_settings.psr_feature_enabled; + bool fs_active_var_en = acrtc->dm_irq_params.freesync_config.state == VRR_STATE_ACTIVE_VARIABLE; + + mod_freesync_handle_v_update(adev->dm.freesync_module, + acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params); + + /* update vmin_vmax only if freesync is enabled, or only if PSR and REPLAY are disabled */ + if (fs_active_var_en || (!fs_active_var_en && !replay_en && !psr_en)) { + schedule_dc_vmin_vmax(adev, acrtc->dm_irq_params.stream, + &acrtc->dm_irq_params.vrr_params.adjust); + } + } + + /* + * If there aren't any active_planes then DCH HUBP may be clock-gated. + * In that case, pageflip completion interrupts won't fire and pageflip + * completion events won't get delivered. Prevent this by sending + * pending pageflip events from here if a flip is still pending. + * + * If any planes are enabled, use dm_pflip_high_irq() instead, to + * avoid race conditions between flip programming and completion, + * which could cause too early flip completion events. + */ + if (adev->family >= AMDGPU_FAMILY_RV && + acrtc->pflip_status == AMDGPU_FLIP_SUBMITTED && + acrtc->dm_irq_params.active_planes == 0) { + if (acrtc->event) { + drm_crtc_send_vblank_event(&acrtc->base, acrtc->event); + acrtc->event = NULL; + drm_crtc_vblank_put(&acrtc->base); + } + acrtc->pflip_status = AMDGPU_FLIP_NONE; + } + + spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags); +} + +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) +/** + * dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for + * DCN generation ASICs + * @interrupt_params: interrupt parameters + * + * Used to set crc window/read out crc value at vertical line 0 position + */ +static void dm_dcn_vertical_interrupt0_high_irq(void *interrupt_params) +{ + struct common_irq_params *irq_params = interrupt_params; + struct amdgpu_device *adev = irq_params->adev; + struct amdgpu_crtc *acrtc; + + acrtc = amdgpu_dm_get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VLINE0); + + if (!acrtc) + return; + + amdgpu_dm_crtc_handle_crc_window_irq(&acrtc->base); +} +#endif /* CONFIG_DRM_AMD_SECURE_DISPLAY */ + +static void dm_handle_hpd_work(struct work_struct *work) +{ + struct dmub_hpd_work *dmub_hpd_wrk; + + dmub_hpd_wrk = container_of(work, struct dmub_hpd_work, handle_hpd_work); + + if (!dmub_hpd_wrk->dmub_notify) { + drm_err(adev_to_drm(dmub_hpd_wrk->adev), "dmub_hpd_wrk dmub_notify is NULL"); + return; + } + + if (dmub_hpd_wrk->dmub_notify->type < ARRAY_SIZE(dmub_hpd_wrk->adev->dm.dmub_callback)) { + dmub_hpd_wrk->adev->dm.dmub_callback[dmub_hpd_wrk->dmub_notify->type](dmub_hpd_wrk->adev, + dmub_hpd_wrk->dmub_notify); + } + + kfree(dmub_hpd_wrk->dmub_notify); + kfree(dmub_hpd_wrk); + +} + +STATIC_IFN_KUNIT const char *dmub_notification_type_str(enum dmub_notification_type e) +{ + switch (e) { + case DMUB_NOTIFICATION_NO_DATA: + return "NO_DATA"; + case DMUB_NOTIFICATION_AUX_REPLY: + return "AUX_REPLY"; + case DMUB_NOTIFICATION_HPD: + return "HPD"; + case DMUB_NOTIFICATION_HPD_IRQ: + return "HPD_IRQ"; + case DMUB_NOTIFICATION_SET_CONFIG_REPLY: + return "SET_CONFIG_REPLY"; + case DMUB_NOTIFICATION_DPIA_NOTIFICATION: + return "DPIA_NOTIFICATION"; + case DMUB_NOTIFICATION_HPD_SENSE_NOTIFY: + return "HPD_SENSE_NOTIFY"; + case DMUB_NOTIFICATION_FUSED_IO: + return "FUSED_IO"; + default: + return ""; + } +} +EXPORT_IF_KUNIT(dmub_notification_type_str); + +#define DMUB_TRACE_MAX_READ 64 +/** + * dm_dmub_outbox1_low_irq() - Handles Outbox interrupt + * @interrupt_params: used for determining the Outbox instance + * + * Handles the Outbox Interrupt + * event handler. + */ +static void dm_dmub_outbox1_low_irq(void *interrupt_params) +{ + struct dmub_notification notify = {0}; + struct common_irq_params *irq_params = interrupt_params; + struct amdgpu_device *adev = irq_params->adev; + struct amdgpu_display_manager *dm = &adev->dm; + struct dmcub_trace_buf_entry entry = { 0 }; + u32 count = 0; + struct dmub_hpd_work *dmub_hpd_wrk; + + do { + if (dc_dmub_srv_get_dmub_outbox0_msg(dm->dc, &entry)) { + trace_amdgpu_dmub_trace_high_irq(entry.trace_code, entry.tick_count, + entry.param0, entry.param1); + + drm_dbg_driver(adev_to_drm(adev), "trace_code:%u, tick_count:%u, param0:%u, param1:%u\n", + entry.trace_code, entry.tick_count, entry.param0, entry.param1); + } else + break; + + count++; + + } while (count <= DMUB_TRACE_MAX_READ); + + if (count > DMUB_TRACE_MAX_READ) + drm_dbg_driver(adev_to_drm(adev), "Warning : count > DMUB_TRACE_MAX_READ"); + + if (dc_enable_dmub_notifications(adev->dm.dc) && + irq_params->irq_src == DC_IRQ_SOURCE_DMCUB_OUTBOX) { + + do { + dc_stat_get_dmub_notification(adev->dm.dc, ¬ify); + if (notify.type >= ARRAY_SIZE(dm->dmub_thread_offload)) { + drm_err(adev_to_drm(adev), "DM: notify type %d invalid!", notify.type); + continue; + } + if (!dm->dmub_callback[notify.type]) { + drm_warn(adev_to_drm(adev), "DMUB notification skipped due to no handler: type=%s\n", + dmub_notification_type_str(notify.type)); + continue; + } + if (dm->dmub_thread_offload[notify.type]) { + dmub_hpd_wrk = kzalloc_obj(*dmub_hpd_wrk, + GFP_ATOMIC); + if (!dmub_hpd_wrk) { + drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk"); + return; + } + dmub_hpd_wrk->dmub_notify = kmemdup(¬ify, sizeof(struct dmub_notification), + GFP_ATOMIC); + if (!dmub_hpd_wrk->dmub_notify) { + kfree(dmub_hpd_wrk); + drm_err(adev_to_drm(adev), "Failed to allocate dmub_hpd_wrk->dmub_notify"); + return; + } + INIT_WORK(&dmub_hpd_wrk->handle_hpd_work, dm_handle_hpd_work); + dmub_hpd_wrk->adev = adev; + queue_work(adev->dm.delayed_hpd_wq, &dmub_hpd_wrk->handle_hpd_work); + } else { + dm->dmub_callback[notify.type](adev, ¬ify); + } + } while (notify.pending_notification); + } +} + +/* Register IRQ sources and initialize IRQ callbacks */ +int amdgpu_dm_dce110_register_irq_handlers(struct amdgpu_device *adev) +{ + struct dc *dc = adev->dm.dc; + struct common_irq_params *c_irq_params; + struct dc_interrupt_params int_params = {0}; + int r; + int i; + unsigned int src_id; + unsigned int client_id = AMDGPU_IRQ_CLIENTID_LEGACY; + /* Use different interrupts for VBLANK on DCE 6 vs. newer. */ + const unsigned int vblank_d1 = + adev->dm.dc->ctx->dce_version >= DCE_VERSION_8_0 + ? VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0 : 1; + + if (adev->family >= AMDGPU_FAMILY_AI) + client_id = SOC15_IH_CLIENTID_DCE; + + int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; + int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; + + /* + * Actions of amdgpu_irq_add_id(): + * 1. Register a set() function with base driver. + * Base driver will call set() function to enable/disable an + * interrupt in DC hardware. + * 2. Register amdgpu_dm_irq_handler(). + * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts + * coming from DC hardware. + * amdgpu_dm_irq_handler() will re-direct the interrupt to DC + * for acknowledging and handling. + */ + + /* Use VBLANK interrupt */ + for (i = 0; i < adev->mode_info.num_crtc; i++) { + src_id = vblank_d1 + i; + r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->crtc_irq); + if (r) { + drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, src_id, 0); + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || + int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { + drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n"); + return -EINVAL; + } + + c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_crtc_high_irq, c_irq_params)) + return -ENOMEM; + } + + if (dc_supports_vrr(adev->dm.dc->ctx->dce_version)) { + /* Use VUPDATE interrupt */ + for (i = 0; i < adev->mode_info.num_crtc; i++) { + src_id = VISLANDS30_IV_SRCID_D1_V_UPDATE_INT + i * 2; + r = amdgpu_irq_add_id(adev, client_id, src_id, &adev->vupdate_irq); + if (r) { + drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, src_id, 0); + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VUPDATE1 || + int_params.irq_source > DC_IRQ_SOURCE_VUPDATE6) { + drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n"); + return -EINVAL; + } + + c_irq_params = &adev->dm.vupdate_params[ + int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_vupdate_high_irq, c_irq_params)) + return -ENOMEM; + } + } + + /* Use GRPH_PFLIP interrupt */ + for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP; + i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) { + r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq); + if (r) { + drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, i, 0); + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || + int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { + drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n"); + return -EINVAL; + } + + c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_pflip_high_irq, c_irq_params)) + return -ENOMEM; + } + + /* HPD */ + r = amdgpu_irq_add_id(adev, client_id, + VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq); + if (r) { + drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n"); + return r; + } + + r = amdgpu_dm_register_hpd_handlers(adev); + + return r; +} + +/* Register IRQ sources and initialize IRQ callbacks */ +int amdgpu_dm_dcn10_register_irq_handlers(struct amdgpu_device *adev) +{ + struct dc *dc = adev->dm.dc; + struct common_irq_params *c_irq_params; + struct dc_interrupt_params int_params = {0}; + int r; + int i; +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + static const unsigned int vrtl_int_srcid[] = { + DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL, + DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL, + DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL, + DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL, + DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL, + DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL + }; +#endif + + int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; + int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; + + /* + * Actions of amdgpu_irq_add_id(): + * 1. Register a set() function with base driver. + * Base driver will call set() function to enable/disable an + * interrupt in DC hardware. + * 2. Register amdgpu_dm_irq_handler(). + * Base driver will call amdgpu_dm_irq_handler() for ALL interrupts + * coming from DC hardware. + * amdgpu_dm_irq_handler() will re-direct the interrupt to DC + * for acknowledging and handling. + */ + + /* Use VSTARTUP interrupt */ + for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP; + i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1; + i++) { + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->crtc_irq); + + if (r) { + drm_err(adev_to_drm(adev), "Failed to add crtc irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, i, 0); + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VBLANK1 || + int_params.irq_source > DC_IRQ_SOURCE_VBLANK6) { + drm_err(adev_to_drm(adev), "Failed to register vblank irq!\n"); + return -EINVAL; + } + + c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_crtc_high_irq, c_irq_params)) + return -ENOMEM; + } + + /* Use otg vertical line interrupt */ +#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY) + for (i = 0; i <= adev->mode_info.num_crtc - 1; i++) { + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, + vrtl_int_srcid[i], &adev->vline0_irq); + + if (r) { + drm_err(adev_to_drm(adev), "Failed to add vline0 irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, vrtl_int_srcid[i], 0); + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_DC1_VLINE0 || + int_params.irq_source > DC_IRQ_SOURCE_DC6_VLINE0) { + drm_err(adev_to_drm(adev), "Failed to register vline0 irq!\n"); + return -EINVAL; + } + + c_irq_params = &adev->dm.vline0_params[int_params.irq_source + - DC_IRQ_SOURCE_DC1_VLINE0]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_dcn_vertical_interrupt0_high_irq, + c_irq_params)) + return -ENOMEM; + } +#endif + + /* Use VUPDATE_NO_LOCK interrupt on DCN, which seems to correspond to + * the regular VUPDATE interrupt on DCE. We want DC_IRQ_SOURCE_VUPDATEx + * to trigger at end of each vblank, regardless of state of the lock, + * matching DCE behaviour. + */ + for (i = DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT; + i <= DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT + adev->mode_info.num_crtc - 1; + i++) { + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->vupdate_irq); + + if (r) { + drm_err(adev_to_drm(adev), "Failed to add vupdate irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, i, 0); + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_VUPDATE1 || + int_params.irq_source > DC_IRQ_SOURCE_VUPDATE6) { + drm_err(adev_to_drm(adev), "Failed to register vupdate irq!\n"); + return -EINVAL; + } + + c_irq_params = &adev->dm.vupdate_params[int_params.irq_source - DC_IRQ_SOURCE_VUPDATE1]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_vupdate_high_irq, c_irq_params)) + return -ENOMEM; + } + + /* Use GRPH_PFLIP interrupt */ + for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT; + i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + dc->caps.max_otg_num - 1; + i++) { + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, i, &adev->pageflip_irq); + if (r) { + drm_err(adev_to_drm(adev), "Failed to add page flip irq id!\n"); + return r; + } + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, i, 0); + + if (int_params.irq_source == DC_IRQ_SOURCE_INVALID || + int_params.irq_source < DC_IRQ_SOURCE_PFLIP_FIRST || + int_params.irq_source > DC_IRQ_SOURCE_PFLIP_LAST) { + drm_err(adev_to_drm(adev), "Failed to register pflip irq!\n"); + return -EINVAL; + } + + c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_pflip_high_irq, c_irq_params)) + return -ENOMEM; + } + + /* HPD */ + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT, + &adev->hpd_irq); + if (r) { + drm_err(adev_to_drm(adev), "Failed to add hpd irq id!\n"); + return r; + } + + r = amdgpu_dm_register_hpd_handlers(adev); + + return r; +} + +/* Register Outbox IRQ sources and initialize IRQ callbacks */ +int amdgpu_dm_register_outbox_irq_handlers(struct amdgpu_device *adev) +{ + struct dc *dc = adev->dm.dc; + struct common_irq_params *c_irq_params; + struct dc_interrupt_params int_params = {0}; + int r, i; + + int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT; + int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT; + + r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_DCE, DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT, + &adev->dmub_outbox_irq); + if (r) { + drm_err(adev_to_drm(adev), "Failed to add outbox irq id!\n"); + return r; + } + + if (dc->ctx->dmub_srv) { + i = DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT; + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = + dc_interrupt_to_irq_source(dc, i, 0); + + c_irq_params = &adev->dm.dmub_outbox_params[0]; + + c_irq_params->adev = adev; + c_irq_params->irq_src = int_params.irq_source; + + if (!amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_dmub_outbox1_low_irq, c_irq_params)) + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h index 4f6b58f4f90d..bccb5d354a9f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h @@ -27,6 +27,14 @@ #include "irq_types.h" /* DAL irq definitions */ +struct amdgpu_device; +struct amdgpu_crtc; +struct amdgpu_display_manager; +struct dc_sink; +struct hpd_rx_irq_offload_work_queue; +struct work_struct; +enum dmub_notification_type; + /* * Display Manager IRQ-related interfaces (for use by DAL). */ @@ -101,4 +109,23 @@ void amdgpu_dm_irq_suspend(struct amdgpu_device *adev); void amdgpu_dm_irq_resume_early(struct amdgpu_device *adev); void amdgpu_dm_irq_resume_late(struct amdgpu_device *adev); +/* HPD handling */ +struct hpd_rx_irq_offload_work_queue *amdgpu_dm_hpd_rx_irq_create_workqueue(struct amdgpu_device *adev); +void amdgpu_dm_hpd_rx_irq_work_suspend(struct amdgpu_display_manager *dm); +int amdgpu_dm_register_hpd_handlers(struct amdgpu_device *adev); +void amdgpu_dm_hdmi_hpd_debounce_work(struct work_struct *work); + +/* IRQ handlers */ +struct amdgpu_crtc *amdgpu_dm_get_crtc_by_otg_inst(struct amdgpu_device *adev, + int otg_inst); +int amdgpu_dm_dce110_register_irq_handlers(struct amdgpu_device *adev); +int amdgpu_dm_dcn10_register_irq_handlers(struct amdgpu_device *adev); +int amdgpu_dm_register_outbox_irq_handlers(struct amdgpu_device *adev); + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +enum dc_irq_source amdgpu_dm_hpd_to_dal_irq_source(unsigned int type); +bool are_sinks_equal(const struct dc_sink *sink1, const struct dc_sink *sink2); +const char *dmub_notification_type_str(enum dmub_notification_type e); +#endif + #endif /* __AMDGPU_DM_IRQ_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h index 4b2864375105..1f910a6a00c0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_kunit_helpers.h @@ -10,6 +10,7 @@ #define STATIC_IFN_KUNIT #define INLINE_IFN_KUNIT inline #define EXPORT_IF_KUNIT(symbol) EXPORT_SYMBOL(symbol) + #else #define STATIC_IFN_KUNIT static #define INLINE_IFN_KUNIT diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index b3af7445b457..0546efea5de1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -34,16 +34,17 @@ #include "dm_services.h" #include "amdgpu.h" #include "amdgpu_dm.h" +#include "dmub_cmd.h" #include "amdgpu_dm_mst_types.h" #include "amdgpu_dm_hdcp.h" #include "dc.h" #include "dm_helpers.h" +#include "amdgpu_dm_kunit_helpers.h" #include "ddc_service_types.h" #include "dpcd_defs.h" -#include "dmub_cmd.h" #if defined(CONFIG_DEBUG_FS) #include "amdgpu_dm_debugfs.h" #endif @@ -52,11 +53,54 @@ #define PEAK_FACTOR_X1000 1006 +/* + * Translate a failed AUX transaction's operation result into an errno-style + * return value. @result is returned unchanged for AUX_RET_SUCCESS. + */ +STATIC_IFN_KUNIT ssize_t dm_dp_aux_transfer_result(ssize_t result, + enum aux_return_code_type operation_result) +{ + switch (operation_result) { + case AUX_RET_SUCCESS: + break; + case AUX_RET_ERROR_HPD_DISCON: + case AUX_RET_ERROR_UNKNOWN: + case AUX_RET_ERROR_INVALID_OPERATION: + case AUX_RET_ERROR_PROTOCOL_ERROR: + result = -EIO; + break; + case AUX_RET_ERROR_INVALID_REPLY: + case AUX_RET_ERROR_ENGINE_ACQUIRE: + result = -EBUSY; + break; + case AUX_RET_ERROR_TIMEOUT: + result = -ETIMEDOUT; + break; + } + + return result; +} +EXPORT_IF_KUNIT(dm_dp_aux_transfer_result); + +/* + * Derive the AUX payload transaction flags from a DP AUX request field. + */ +STATIC_IFN_KUNIT void dm_dp_aux_fill_payload_flags(u8 request, + struct aux_payload *payload) +{ + payload->i2c_over_aux = (request & DP_AUX_NATIVE_WRITE) == 0; + payload->write = (request & DP_AUX_I2C_READ) == 0; + payload->mot = (request & DP_AUX_I2C_MOT) != 0; + payload->write_status_update = + (request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0; +} +EXPORT_IF_KUNIT(dm_dp_aux_fill_payload_flags); + /* * This function handles both native AUX and I2C-Over-AUX transactions. */ -static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, - struct drm_dp_aux_msg *msg) +STATIC_IFN_KUNIT ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) { ssize_t result = 0; struct aux_payload payload; @@ -72,11 +116,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, payload.data = msg->buffer; payload.length = msg->size; payload.reply = &msg->reply; - payload.i2c_over_aux = (msg->request & DP_AUX_NATIVE_WRITE) == 0; - payload.write = (msg->request & DP_AUX_I2C_READ) == 0; - payload.mot = (msg->request & DP_AUX_I2C_MOT) != 0; - payload.write_status_update = - (msg->request & DP_AUX_I2C_WRITE_STATUS_UPDATE) != 0; + dm_dp_aux_fill_payload_flags(msg->request, &payload); payload.defer_delay = 0; if (payload.write) { @@ -116,23 +156,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, } if (result < 0) { - switch (operation_result) { - case AUX_RET_SUCCESS: - break; - case AUX_RET_ERROR_HPD_DISCON: - case AUX_RET_ERROR_UNKNOWN: - case AUX_RET_ERROR_INVALID_OPERATION: - case AUX_RET_ERROR_PROTOCOL_ERROR: - result = -EIO; - break; - case AUX_RET_ERROR_INVALID_REPLY: - case AUX_RET_ERROR_ENGINE_ACQUIRE: - result = -EBUSY; - break; - case AUX_RET_ERROR_TIMEOUT: - result = -ETIMEDOUT; - break; - } + result = dm_dp_aux_transfer_result(result, operation_result); drm_dbg_dp(adev_to_drm(adev), "DP AUX transfer fail:%d\n", operation_result); } @@ -143,6 +167,7 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, return result; } +EXPORT_IF_KUNIT(dm_dp_aux_transfer); static void dm_dp_mst_connector_destroy(struct drm_connector *connector) @@ -183,7 +208,7 @@ amdgpu_dm_mst_connector_late_register(struct drm_connector *connector) } -static inline void +STATIC_IFN_KUNIT void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector) { aconnector->drm_edid = NULL; @@ -192,6 +217,7 @@ amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector aconnector->mst_local_bw = 0; aconnector->vc_full_pbn = 0; } +EXPORT_IF_KUNIT(amdgpu_dm_mst_reset_mst_connector_setting); static void amdgpu_dm_mst_connector_early_unregister(struct drm_connector *connector) @@ -248,6 +274,7 @@ bool needs_dsc_aux_workaround(struct dc_link *link) return false; } +EXPORT_IF_KUNIT(needs_dsc_aux_workaround); #if defined(CONFIG_DRM_AMD_DC_FP) static bool is_synaptics_cascaded_panamera(struct dc_link *link, struct drm_dp_mst_port *port) @@ -311,7 +338,7 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto } #endif -static bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector) +STATIC_IFN_KUNIT bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector) { union dp_downstream_port_present ds_port_present; @@ -329,8 +356,9 @@ static bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnect return true; } +EXPORT_IF_KUNIT(retrieve_downstream_port_device); -static bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector) +STATIC_IFN_KUNIT bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector) { struct drm_connector *connector = &aconnector->base; struct drm_dp_mst_port *port = aconnector->mst_output_port; @@ -357,15 +385,13 @@ static bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector return true; } +EXPORT_IF_KUNIT(retrieve_branch_specific_data); static int dm_dp_mst_get_modes(struct drm_connector *connector) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); int ret = 0; - if (!aconnector) - return drm_add_edid_modes(connector, NULL); - if (!aconnector->drm_edid) { const struct drm_edid *drm_edid; @@ -456,7 +482,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) * plugged back with same display index, its hdcp properties * will be retrieved from hdcp_work within dm_dp_mst_get_modes */ - if (aconnector->dc_sink && connector->state) { + if (connector->state) { struct drm_device *dev = connector->dev; struct amdgpu_device *adev = drm_to_adev(dev); @@ -472,20 +498,18 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) } } - if (aconnector->dc_sink) { - amdgpu_dm_update_freesync_caps( - connector, aconnector->drm_edid, true); + amdgpu_dm_update_freesync_caps( + connector, aconnector->drm_edid, true); #if defined(CONFIG_DRM_AMD_DC_FP) - if (!validate_dsc_caps_on_connector(aconnector)) - memset(&aconnector->dc_sink->dsc_caps, - 0, sizeof(aconnector->dc_sink->dsc_caps)); + if (!validate_dsc_caps_on_connector(aconnector)) + memset(&aconnector->dc_sink->dsc_caps, + 0, sizeof(aconnector->dc_sink->dsc_caps)); #endif - if (!retrieve_downstream_port_device(aconnector)) - memset(&aconnector->mst_downstream_port_present, - 0, sizeof(aconnector->mst_downstream_port_present)); - } + if (!retrieve_downstream_port_device(aconnector)) + memset(&aconnector->mst_downstream_port_present, + 0, sizeof(aconnector->mst_downstream_port_present)); } drm_edid_connector_update(&aconnector->base, aconnector->drm_edid); @@ -495,7 +519,7 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector) return ret; } -static struct drm_encoder * +STATIC_IFN_KUNIT struct drm_encoder * dm_mst_atomic_best_encoder(struct drm_connector *connector, struct drm_atomic_commit *state) { @@ -506,8 +530,9 @@ dm_mst_atomic_best_encoder(struct drm_connector *connector, return &adev->dm.mst_encoders[acrtc->crtc_id].base; } +EXPORT_IF_KUNIT(dm_mst_atomic_best_encoder); -static int +STATIC_IFN_KUNIT int dm_dp_mst_detect(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx, bool force) { @@ -577,9 +602,10 @@ dm_dp_mst_detect(struct drm_connector *connector, return connection_status; } +EXPORT_IF_KUNIT(dm_dp_mst_detect); -static int dm_dp_mst_atomic_check(struct drm_connector *connector, - struct drm_atomic_commit *state) +STATIC_IFN_KUNIT int dm_dp_mst_atomic_check(struct drm_connector *connector, + struct drm_atomic_commit *state) { struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector); struct drm_dp_mst_topology_mgr *mst_mgr = &aconnector->mst_root->mst_mgr; @@ -587,6 +613,7 @@ static int dm_dp_mst_atomic_check(struct drm_connector *connector, return drm_dp_atomic_release_time_slots(state, mst_mgr, mst_port); } +EXPORT_IF_KUNIT(dm_dp_mst_atomic_check); static const struct drm_connector_helper_funcs dm_dp_mst_connector_helper_funcs = { .get_modes = dm_dp_mst_get_modes, @@ -627,6 +654,7 @@ dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev) drm_encoder_helper_add(encoder, &amdgpu_dm_encoder_helper_funcs); } } +EXPORT_IF_KUNIT(dm_dp_create_fake_mst_encoders); static struct drm_connector * dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, @@ -711,6 +739,44 @@ dm_dp_add_mst_connector(struct drm_dp_mst_topology_mgr *mgr, return connector; } +/* + * Select the ESI[1] mask used to filter the MST sideband ready bits for a + * given message-ready event type. + */ +STATIC_IFN_KUNIT u8 dm_mst_msg_ready_mask(enum mst_msg_ready_type msg_rdy_type) +{ + switch (msg_rdy_type) { + case DOWN_REP_MSG_RDY_EVENT: + /* Only handle DOWN_REP_MSG_RDY case*/ + return DP_DOWN_REP_MSG_RDY; + case UP_REQ_MSG_RDY_EVENT: + /* Only handle UP_REQ_MSG_RDY case*/ + return DP_UP_REQ_MSG_RDY; + default: + /* Handle both cases*/ + return DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY; + } +} +EXPORT_IF_KUNIT(dm_mst_msg_ready_mask); + +/* + * Select the DPCD ESI address and read length based on the DPCD revision. + */ +STATIC_IFN_KUNIT void dm_mst_select_esi_dpcd(u8 dpcd_rev, int *dpcd_addr, + u8 *dpcd_bytes_to_read) +{ + if (dpcd_rev < 0x12) { + *dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT; + /* DPCD 0x200 - 0x201 for downstream IRQ */ + *dpcd_addr = DP_SINK_COUNT; + } else { + *dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI; + /* DPCD 0x2002 - 0x2005 for downstream IRQ */ + *dpcd_addr = DP_SINK_COUNT_ESI; + } +} +EXPORT_IF_KUNIT(dm_mst_select_esi_dpcd); + void dm_handle_mst_sideband_msg_ready_event( struct drm_dp_mst_topology_mgr *mgr, enum mst_msg_ready_type msg_rdy_type) @@ -729,15 +795,8 @@ void dm_handle_mst_sideband_msg_ready_event( const struct dc_link_status *link_status = dc_link_get_status(aconnector->dc_link); - if (link_status->dpcd_caps->dpcd_rev.raw < 0x12) { - dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT; - /* DPCD 0x200 - 0x201 for downstream IRQ */ - dpcd_addr = DP_SINK_COUNT; - } else { - dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI; - /* DPCD 0x2002 - 0x2005 for downstream IRQ */ - dpcd_addr = DP_SINK_COUNT_ESI; - } + dm_mst_select_esi_dpcd(link_status->dpcd_caps->dpcd_rev.raw, &dpcd_addr, + &dpcd_bytes_to_read); mutex_lock(&aconnector->handle_mst_msg_ready); @@ -759,20 +818,7 @@ void dm_handle_mst_sideband_msg_ready_event( DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]); - switch (msg_rdy_type) { - case DOWN_REP_MSG_RDY_EVENT: - /* Only handle DOWN_REP_MSG_RDY case*/ - esi[1] &= DP_DOWN_REP_MSG_RDY; - break; - case UP_REQ_MSG_RDY_EVENT: - /* Only handle UP_REQ_MSG_RDY case*/ - esi[1] &= DP_UP_REQ_MSG_RDY; - break; - default: - /* Handle both cases*/ - esi[1] &= (DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY); - break; - } + esi[1] &= dm_mst_msg_ready_mask(msg_rdy_type); if (!esi[1]) break; @@ -814,6 +860,7 @@ void dm_handle_mst_sideband_msg_ready_event( if (process_count == max_process_count) DRM_DEBUG_DRIVER("Loop exceeded max iterations\n"); } +EXPORT_IF_KUNIT(dm_handle_mst_sideband_msg_ready_event); static void dm_handle_mst_down_rep_msg_ready(struct drm_dp_mst_topology_mgr *mgr) { @@ -869,6 +916,7 @@ uint32_t dm_mst_get_pbn_divider(struct dc_link *link) return dfixed_const(pbn_div_x100) / 100; } +EXPORT_IF_KUNIT(dm_mst_get_pbn_divider); struct dsc_mst_fairness_params { struct dc_crtc_timing *timing; @@ -1787,7 +1835,7 @@ int pre_validate_dsc(struct drm_atomic_commit *state, dm_old_crtc_state = to_dm_crtc_state(state->crtcs[ind].old_state); local_dc_state->streams[i] = - create_validate_stream_for_sink(connector, + amdgpu_dm_create_validate_stream_for_sink(connector, &state->crtcs[ind].new_state->mode, dm_new_conn_state, dm_old_crtc_state->stream); @@ -2066,3 +2114,4 @@ enum dc_status dm_dp_mst_is_port_support_mode( #endif return DC_OK; } +EXPORT_IF_KUNIT(dm_dp_mst_is_port_support_mode); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h index 0e8eef5bdb74..fecf108a9216 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h @@ -57,8 +57,15 @@ enum mst_msg_ready_type { DOWN_OR_UP_MSG_RDY_EVENT = 3 }; +struct amdgpu_device; struct amdgpu_display_manager; struct amdgpu_dm_connector; +struct aux_payload; +struct dc_state; +struct dc_stream_state; +struct dm_atomic_state; +struct drm_atomic_commit; +struct drm_dp_mst_topology_mgr; uint32_t dm_mst_get_pbn_divider(struct dc_link *link); @@ -94,4 +101,22 @@ enum dc_status dm_dp_mst_is_port_support_mode( struct amdgpu_dm_connector *aconnector, struct dc_stream_state *stream); +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +void amdgpu_dm_mst_reset_mst_connector_setting(struct amdgpu_dm_connector *aconnector); +bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector); +bool retrieve_branch_specific_data(struct amdgpu_dm_connector *aconnector); +ssize_t dm_dp_aux_transfer_result(ssize_t result, + enum aux_return_code_type operation_result); +void dm_dp_aux_fill_payload_flags(u8 request, struct aux_payload *payload); +ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg); +u8 dm_mst_msg_ready_mask(enum mst_msg_ready_type msg_rdy_type); +void dm_mst_select_esi_dpcd(u8 dpcd_rev, int *dpcd_addr, u8 *dpcd_bytes_to_read); +struct drm_encoder *dm_mst_atomic_best_encoder(struct drm_connector *connector, + struct drm_atomic_commit *state); +int dm_dp_mst_atomic_check(struct drm_connector *connector, + struct drm_atomic_commit *state); +int dm_dp_mst_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, bool force); +#endif + #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c index c7f8e08feaf4..1b564cfe2120 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c @@ -37,6 +37,7 @@ #include "amdgpu_display.h" #include "amdgpu_dm_trace.h" #include "amdgpu_dm_plane.h" +#include "amdgpu_dm_kunit_helpers.h" #include "amdgpu_dm_colorop.h" #include "gc/gc_11_0_0_offset.h" #include "gc/gc_11_0_0_sh_mask.h" @@ -97,6 +98,7 @@ const struct drm_format_info *amdgpu_dm_plane_get_format_info(u32 pixel_format, { return amdgpu_lookup_format_info(pixel_format, modifier); } +EXPORT_IF_KUNIT(amdgpu_dm_plane_get_format_info); void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state *plane_state, bool *per_pixel_alpha, bool *pre_multiplied_alpha, @@ -135,12 +137,24 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state } if (plane_state->alpha < 0xffff) { + struct amdgpu_device *adev = drm_to_adev(plane_state->plane->dev); *global_alpha = true; - *global_alpha_value = plane_state->alpha >> 8; + /* + * DCN 4.2 uses a 12-bit MPCC_GLOBAL_ALPHA field, while + * other ASICs use an 8-bit field. The DRM plane alpha is + * 16-bit, so scale it down to the width the hardware expects. + */ + if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 2, 0)) + *global_alpha_value = plane_state->alpha >> 4; + else + *global_alpha_value = plane_state->alpha >> 8; + } } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_blending_from_plane_state); -static void amdgpu_dm_plane_add_modifier(uint64_t **mods, uint64_t *size, uint64_t *cap, uint64_t mod) +STATIC_IFN_KUNIT void amdgpu_dm_plane_add_modifier(uint64_t **mods, uint64_t *size, + uint64_t *cap, uint64_t mod) { if (!*mods) return; @@ -164,27 +178,29 @@ static void amdgpu_dm_plane_add_modifier(uint64_t **mods, uint64_t *size, uint64 (*mods)[*size] = mod; *size += 1; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_add_modifier); -static bool amdgpu_dm_plane_modifier_has_dcc(uint64_t modifier) +STATIC_IFN_KUNIT bool amdgpu_dm_plane_modifier_has_dcc(uint64_t modifier) { return IS_AMD_FMT_MOD(modifier) && AMD_FMT_MOD_GET(DCC, modifier); } +EXPORT_IF_KUNIT(amdgpu_dm_plane_modifier_has_dcc); -static unsigned int amdgpu_dm_plane_modifier_gfx9_swizzle_mode(uint64_t modifier) +STATIC_IFN_KUNIT unsigned int amdgpu_dm_plane_modifier_gfx9_swizzle_mode(uint64_t modifier) { if (modifier == DRM_FORMAT_MOD_LINEAR) return 0; return AMD_FMT_MOD_GET(TILE, modifier); } +EXPORT_IF_KUNIT(amdgpu_dm_plane_modifier_gfx9_swizzle_mode); -static void amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(struct dc_tiling_info *tiling_info, - uint64_t tiling_flags) +STATIC_IFN_KUNIT void amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(struct dc_tiling_info *tiling_info, + uint64_t tiling_flags) { /* Fill GFX8 params */ if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) { unsigned int bankw, bankh, mtaspect, tile_split, num_banks; - bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH); bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT); mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT); @@ -210,9 +226,10 @@ static void amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(struct dc_tiling_in tiling_info->gfx8.pipe_config = AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG); } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags); -static void amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev, - struct dc_tiling_info *tiling_info) +STATIC_IFN_KUNIT void amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev, + struct dc_tiling_info *tiling_info) { /* Fill GFX9 params */ tiling_info->gfx9.num_pipes = @@ -231,10 +248,11 @@ static void amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(const struct amdgp if (amdgpu_ip_version(adev, GC_HWIP, 0) >= IP_VERSION(10, 3, 0)) tiling_info->gfx9.num_pkrs = adev->gfx.config.gb_addr_config_fields.num_pkrs; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_tiling_info_from_device); -static void amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev, - struct dc_tiling_info *tiling_info, - uint64_t modifier) +STATIC_IFN_KUNIT void amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev, + struct dc_tiling_info *tiling_info, + uint64_t modifier) { unsigned int mod_bank_xor_bits = AMD_FMT_MOD_GET(BANK_XOR_BITS, modifier); unsigned int mod_pipe_xor_bits = AMD_FMT_MOD_GET(PIPE_XOR_BITS, modifier); @@ -259,14 +277,15 @@ static void amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(const struct amd /* for DCC we know it isn't rb aligned, so rb_per_se doesn't matter. */ } } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier); -static int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev, - const enum surface_pixel_format format, - const enum dc_rotation_angle rotation, - const struct dc_tiling_info *tiling_info, - const struct dc_plane_dcc_param *dcc, - const struct dc_plane_address *address, - const struct plane_size *plane_size) +STATIC_IFN_KUNIT int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const struct dc_tiling_info *tiling_info, + const struct dc_plane_dcc_param *dcc, + const struct dc_plane_address *address, + const struct plane_size *plane_size) { struct dc *dc = adev->dm.dc; struct dc_dcc_surface_param input; @@ -307,15 +326,16 @@ static int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev, return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_validate_dcc); -static int amdgpu_dm_plane_fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev, - const struct amdgpu_framebuffer *afb, - const enum surface_pixel_format format, - const enum dc_rotation_angle rotation, - const struct plane_size *plane_size, - struct dc_tiling_info *tiling_info, - struct dc_plane_dcc_param *dcc, - struct dc_plane_address *address) +STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev, + const struct amdgpu_framebuffer *afb, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const struct plane_size *plane_size, + struct dc_tiling_info *tiling_info, + struct dc_plane_dcc_param *dcc, + struct dc_plane_address *address) { const uint64_t modifier = afb->base.modifier; int ret = 0; @@ -358,15 +378,16 @@ static int amdgpu_dm_plane_fill_gfx9_plane_attributes_from_modifiers(struct amdg return ret; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx9_plane_attributes_from_modifiers); -static int amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers(struct amdgpu_device *adev, - const struct amdgpu_framebuffer *afb, - const enum surface_pixel_format format, - const enum dc_rotation_angle rotation, - const struct plane_size *plane_size, - struct dc_tiling_info *tiling_info, - struct dc_plane_dcc_param *dcc, - struct dc_plane_address *address) +STATIC_IFN_KUNIT int amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers(struct amdgpu_device *adev, + const struct amdgpu_framebuffer *afb, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const struct plane_size *plane_size, + struct dc_tiling_info *tiling_info, + struct dc_plane_dcc_param *dcc, + struct dc_plane_address *address) { const uint64_t modifier = afb->base.modifier; int ret = 0; @@ -398,6 +419,7 @@ static int amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers(struct amd return ret; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers); static void amdgpu_dm_plane_add_gfx10_1_modifiers(const struct amdgpu_device *adev, uint64_t **mods, @@ -724,7 +746,7 @@ static void amdgpu_dm_plane_add_gfx12_modifiers(struct amdgpu_device *adev, } -static int amdgpu_dm_plane_get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods) +STATIC_IFN_KUNIT int amdgpu_dm_plane_get_plane_modifiers(struct amdgpu_device *adev, unsigned int plane_type, uint64_t **mods) { uint64_t size = 0, capacity = 128; *mods = NULL; @@ -777,10 +799,11 @@ static int amdgpu_dm_plane_get_plane_modifiers(struct amdgpu_device *adev, unsig return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_get_plane_modifiers); -static int amdgpu_dm_plane_get_plane_formats(const struct drm_plane *plane, - const struct dc_plane_cap *plane_cap, - uint32_t *formats, int max_formats) +STATIC_IFN_KUNIT int amdgpu_dm_plane_get_plane_formats(const struct drm_plane *plane, + const struct dc_plane_cap *plane_cap, + uint32_t *formats, int max_formats) { int i, num_formats = 0; @@ -836,6 +859,7 @@ static int amdgpu_dm_plane_get_plane_formats(const struct drm_plane *plane, return num_formats; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_get_plane_formats); int amdgpu_dm_plane_fill_plane_buffer_attributes(struct amdgpu_device *adev, const struct amdgpu_framebuffer *afb, @@ -922,6 +946,7 @@ int amdgpu_dm_plane_fill_plane_buffer_attributes(struct amdgpu_device *adev, return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_plane_buffer_attributes); static int amdgpu_dm_plane_helper_prepare_fb(struct drm_plane *plane, struct drm_plane_state *new_state) @@ -1042,9 +1067,9 @@ static void amdgpu_dm_plane_helper_cleanup_fb(struct drm_plane *plane, amdgpu_bo_unref(&rbo); } -static void amdgpu_dm_plane_get_min_max_dc_plane_scaling(struct drm_device *dev, - struct drm_framebuffer *fb, - int *min_downscale, int *max_upscale) +STATIC_IFN_KUNIT void amdgpu_dm_plane_get_min_max_dc_plane_scaling(struct drm_device *dev, + struct drm_framebuffer *fb, + int *min_downscale, int *max_upscale) { struct amdgpu_device *adev = drm_to_adev(dev); struct dc *dc = adev->dm.dc; @@ -1088,6 +1113,7 @@ static void amdgpu_dm_plane_get_min_max_dc_plane_scaling(struct drm_device *dev, if (*min_downscale == 1) *min_downscale = 1000; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_get_min_max_dc_plane_scaling); int amdgpu_dm_plane_helper_check_state(struct drm_plane_state *state, struct drm_crtc_state *new_crtc_state) @@ -1142,6 +1168,7 @@ int amdgpu_dm_plane_helper_check_state(struct drm_plane_state *state, return drm_atomic_helper_check_plane_state( state, new_crtc_state, min_scale, max_scale, true, true); } +EXPORT_IF_KUNIT(amdgpu_dm_plane_helper_check_state); int amdgpu_dm_plane_fill_dc_scaling_info(struct amdgpu_device *adev, const struct drm_plane_state *state, @@ -1225,6 +1252,7 @@ int amdgpu_dm_plane_fill_dc_scaling_info(struct amdgpu_device *adev, return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_fill_dc_scaling_info); static int amdgpu_dm_plane_atomic_check(struct drm_plane *plane, struct drm_atomic_commit *state) @@ -1343,6 +1371,7 @@ int amdgpu_dm_plane_get_cursor_position(struct drm_plane *plane, struct drm_crtc return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_get_cursor_position); void amdgpu_dm_plane_handle_cursor_update(struct drm_plane *plane, struct drm_plane_state *old_plane_state) @@ -1488,17 +1517,15 @@ static const struct drm_plane_helper_funcs dm_primary_plane_helper_funcs = { static void amdgpu_dm_plane_drm_plane_reset(struct drm_plane *plane) { - struct dm_plane_state *amdgpu_state = NULL; + struct dm_plane_state *amdgpu_state; + + amdgpu_state = kzalloc_obj(*amdgpu_state); + if (!amdgpu_state) + return; if (plane->state) plane->funcs->atomic_destroy_state(plane, plane->state); - amdgpu_state = kzalloc_obj(*amdgpu_state); - WARN_ON(amdgpu_state == NULL); - - if (!amdgpu_state) - return; - __drm_atomic_helper_plane_reset(plane, &amdgpu_state->base); amdgpu_state->degamma_tf = AMDGPU_TRANSFER_FUNCTION_DEFAULT; amdgpu_state->hdr_mult = AMDGPU_HDR_MULT_DEFAULT; @@ -1546,9 +1573,9 @@ static struct drm_plane_state *amdgpu_dm_plane_drm_plane_duplicate_state(struct return &dm_plane_state->base; } -static bool amdgpu_dm_plane_format_mod_supported(struct drm_plane *plane, - uint32_t format, - uint64_t modifier) +STATIC_IFN_KUNIT bool amdgpu_dm_plane_format_mod_supported(struct drm_plane *plane, + uint32_t format, + uint64_t modifier) { struct amdgpu_device *adev = drm_to_adev(plane->dev); const struct drm_format_info *info = drm_format_info(format); @@ -1607,6 +1634,7 @@ static bool amdgpu_dm_plane_format_mod_supported(struct drm_plane *plane, return true; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_format_mod_supported); static void amdgpu_dm_plane_drm_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) @@ -1982,4 +2010,5 @@ bool amdgpu_dm_plane_is_video_format(uint32_t format) return false; } +EXPORT_IF_KUNIT(amdgpu_dm_plane_is_video_format); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h index ea2619b507db..911fb2d73e22 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.h @@ -28,6 +28,8 @@ #define __AMDGPU_DM_PLANE_H__ #include "dc.h" +#include +#include "amdgpu.h" int amdgpu_dm_plane_get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc, struct dc_cursor_position *position); @@ -65,4 +67,53 @@ void amdgpu_dm_plane_fill_blending_from_plane_state(const struct drm_plane_state bool *global_alpha, int *global_alpha_value); bool amdgpu_dm_plane_is_video_format(uint32_t format); + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +void amdgpu_dm_plane_add_modifier(uint64_t **mods, uint64_t *size, + uint64_t *cap, uint64_t mod); +void amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(struct dc_tiling_info *tiling_info, + uint64_t tiling_flags); +void amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(const struct amdgpu_device *adev, + struct dc_tiling_info *tiling_info); +void amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(const struct amdgpu_device *adev, + struct dc_tiling_info *tiling_info, + uint64_t modifier); +int amdgpu_dm_plane_validate_dcc(struct amdgpu_device *adev, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const struct dc_tiling_info *tiling_info, + const struct dc_plane_dcc_param *dcc, + const struct dc_plane_address *address, + const struct plane_size *plane_size); +bool amdgpu_dm_plane_modifier_has_dcc(uint64_t modifier); +unsigned int amdgpu_dm_plane_modifier_gfx9_swizzle_mode(uint64_t modifier); +int amdgpu_dm_plane_get_plane_modifiers(struct amdgpu_device *adev, + unsigned int plane_type, uint64_t **mods); +int amdgpu_dm_plane_get_plane_formats(const struct drm_plane *plane, + const struct dc_plane_cap *plane_cap, + uint32_t *formats, int max_formats); +int amdgpu_dm_plane_fill_gfx9_plane_attributes_from_modifiers(struct amdgpu_device *adev, + const struct amdgpu_framebuffer *afb, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const struct plane_size *plane_size, + struct dc_tiling_info *tiling_info, + struct dc_plane_dcc_param *dcc, + struct dc_plane_address *address); +int amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers(struct amdgpu_device *adev, + const struct amdgpu_framebuffer *afb, + const enum surface_pixel_format format, + const enum dc_rotation_angle rotation, + const struct plane_size *plane_size, + struct dc_tiling_info *tiling_info, + struct dc_plane_dcc_param *dcc, + struct dc_plane_address *address); +bool amdgpu_dm_plane_format_mod_supported(struct drm_plane *plane, + uint32_t format, + uint64_t modifier); +void amdgpu_dm_plane_get_min_max_dc_plane_scaling(struct drm_device *dev, + struct drm_framebuffer *fb, + int *min_downscale, + int *max_upscale); +#endif #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c index 2cdb8fea504a..0d2e5294d062 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c @@ -33,73 +33,67 @@ #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" #include "dm_pp_smu.h" +#include "amdgpu_dm_kunit_helpers.h" +#include "amdgpu_dm_pp_smu.h" + +STATIC_IFN_KUNIT void build_pm_display_cfg( + struct amd_pp_display_configuration *pm_display_cfg, + const struct dm_pp_display_configuration *pp_display_cfg) +{ + int i; + + memset(pm_display_cfg, 0, sizeof(*pm_display_cfg)); + + pm_display_cfg->cpu_cc6_disable = pp_display_cfg->cpu_cc6_disable; + pm_display_cfg->cpu_pstate_disable = pp_display_cfg->cpu_pstate_disable; + pm_display_cfg->cpu_pstate_separation_time = pp_display_cfg->cpu_pstate_separation_time; + pm_display_cfg->nb_pstate_switch_disable = pp_display_cfg->nb_pstate_switch_disable; + + pm_display_cfg->num_display = pp_display_cfg->display_count; + pm_display_cfg->num_path_including_non_display = pp_display_cfg->display_count; + + pm_display_cfg->min_core_set_clock = pp_display_cfg->min_engine_clock_khz/10; + pm_display_cfg->min_core_set_clock_in_sr = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + pm_display_cfg->min_mem_set_clock = pp_display_cfg->min_memory_clock_khz/10; + + pm_display_cfg->min_dcef_deep_sleep_set_clk = + pp_display_cfg->min_engine_clock_deep_sleep_khz/10; + pm_display_cfg->min_dcef_set_clk = pp_display_cfg->min_dcfclock_khz/10; + + pm_display_cfg->multi_monitor_in_sync = pp_display_cfg->all_displays_in_sync; + pm_display_cfg->min_vblank_time = pp_display_cfg->avail_mclk_switch_time_us; + + pm_display_cfg->display_clk = pp_display_cfg->disp_clk_khz/10; + + pm_display_cfg->dce_tolerable_mclk_in_active_latency = + pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; + + pm_display_cfg->crtc_index = pp_display_cfg->crtc_index; + pm_display_cfg->line_time_in_us = pp_display_cfg->line_time_in_us; + + pm_display_cfg->vrefresh = pp_display_cfg->disp_configs[0].v_refresh; + pm_display_cfg->crossfire_display_index = -1; + pm_display_cfg->min_bus_bandwidth = 0; + + for (i = 0; i < pp_display_cfg->display_count; i++) { + const struct dm_pp_single_disp_config *dc_cfg = + &pp_display_cfg->disp_configs[i]; + pm_display_cfg->displays[i].controller_id = dc_cfg->pipe_idx + 1; + pm_display_cfg->displays[i].pixel_clock = dc_cfg->pixel_clock; + } +} +EXPORT_IF_KUNIT(build_pm_display_cfg); bool dm_pp_apply_display_requirements( const struct dc_context *ctx, const struct dm_pp_display_configuration *pp_display_cfg) { struct amdgpu_device *adev = ctx->driver_context; - int i; if (adev->pm.dpm_enabled) { - memset(&adev->pm.pm_display_cfg, 0, - sizeof(adev->pm.pm_display_cfg)); - - adev->pm.pm_display_cfg.cpu_cc6_disable = - pp_display_cfg->cpu_cc6_disable; - - adev->pm.pm_display_cfg.cpu_pstate_disable = - pp_display_cfg->cpu_pstate_disable; - - adev->pm.pm_display_cfg.cpu_pstate_separation_time = - pp_display_cfg->cpu_pstate_separation_time; - - adev->pm.pm_display_cfg.nb_pstate_switch_disable = - pp_display_cfg->nb_pstate_switch_disable; - - adev->pm.pm_display_cfg.num_display = - pp_display_cfg->display_count; - adev->pm.pm_display_cfg.num_path_including_non_display = - pp_display_cfg->display_count; - - adev->pm.pm_display_cfg.min_core_set_clock = - pp_display_cfg->min_engine_clock_khz/10; - adev->pm.pm_display_cfg.min_core_set_clock_in_sr = - pp_display_cfg->min_engine_clock_deep_sleep_khz/10; - adev->pm.pm_display_cfg.min_mem_set_clock = - pp_display_cfg->min_memory_clock_khz/10; - - adev->pm.pm_display_cfg.min_dcef_deep_sleep_set_clk = - pp_display_cfg->min_engine_clock_deep_sleep_khz/10; - adev->pm.pm_display_cfg.min_dcef_set_clk = - pp_display_cfg->min_dcfclock_khz/10; - - adev->pm.pm_display_cfg.multi_monitor_in_sync = - pp_display_cfg->all_displays_in_sync; - adev->pm.pm_display_cfg.min_vblank_time = - pp_display_cfg->avail_mclk_switch_time_us; - - adev->pm.pm_display_cfg.display_clk = - pp_display_cfg->disp_clk_khz/10; - - adev->pm.pm_display_cfg.dce_tolerable_mclk_in_active_latency = - pp_display_cfg->avail_mclk_switch_time_in_disp_active_us; - - adev->pm.pm_display_cfg.crtc_index = pp_display_cfg->crtc_index; - adev->pm.pm_display_cfg.line_time_in_us = - pp_display_cfg->line_time_in_us; - - adev->pm.pm_display_cfg.vrefresh = pp_display_cfg->disp_configs[0].v_refresh; - adev->pm.pm_display_cfg.crossfire_display_index = -1; - adev->pm.pm_display_cfg.min_bus_bandwidth = 0; - - for (i = 0; i < pp_display_cfg->display_count; i++) { - const struct dm_pp_single_disp_config *dc_cfg = - &pp_display_cfg->disp_configs[i]; - adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; - adev->pm.pm_display_cfg.displays[i].pixel_clock = dc_cfg->pixel_clock; - } + build_pm_display_cfg(&adev->pm.pm_display_cfg, pp_display_cfg); amdgpu_dpm_display_configuration_change(adev, &adev->pm.pm_display_cfg); @@ -108,8 +102,9 @@ bool dm_pp_apply_display_requirements( return true; } +EXPORT_IF_KUNIT(dm_pp_apply_display_requirements); -static void get_default_clock_levels( +STATIC_IFN_KUNIT void get_default_clock_levels( enum dm_pp_clock_type clk_type, struct dm_pp_clock_levels *clks) { @@ -140,8 +135,9 @@ static void get_default_clock_levels( break; } } +EXPORT_IF_KUNIT(get_default_clock_levels); -static enum amd_pp_clock_type dc_to_pp_clock_type( +STATIC_IFN_KUNIT enum amd_pp_clock_type dc_to_pp_clock_type( enum dm_pp_clock_type dm_pp_clk_type) { enum amd_pp_clock_type amd_pp_clk_type = 0; @@ -182,8 +178,9 @@ static enum amd_pp_clock_type dc_to_pp_clock_type( return amd_pp_clk_type; } +EXPORT_IF_KUNIT(dc_to_pp_clock_type); -static void pp_to_dc_clock_levels( +STATIC_IFN_KUNIT void pp_to_dc_clock_levels( const struct amd_pp_clocks *pp_clks, struct dm_pp_clock_levels *dc_clks, enum dm_pp_clock_type dc_clk_type) @@ -208,8 +205,9 @@ static void pp_to_dc_clock_levels( dc_clks->clocks_in_khz[i] = pp_clks->clock[i]; } } +EXPORT_IF_KUNIT(pp_to_dc_clock_levels); -static void pp_to_dc_clock_levels_with_latency( +STATIC_IFN_KUNIT void pp_to_dc_clock_levels_with_latency( const struct pp_clock_levels_with_latency *pp_clks, struct dm_pp_clock_levels_with_latency *clk_level_info, enum dm_pp_clock_type dc_clk_type) @@ -235,8 +233,9 @@ static void pp_to_dc_clock_levels_with_latency( clk_level_info->data[i].latency_in_us = pp_clks->data[i].latency_in_us; } } +EXPORT_IF_KUNIT(pp_to_dc_clock_levels_with_latency); -static void pp_to_dc_clock_levels_with_voltage( +STATIC_IFN_KUNIT void pp_to_dc_clock_levels_with_voltage( const struct pp_clock_levels_with_voltage *pp_clks, struct dm_pp_clock_levels_with_voltage *clk_level_info, enum dm_pp_clock_type dc_clk_type) @@ -263,6 +262,41 @@ static void pp_to_dc_clock_levels_with_voltage( clk_level_info->data[i].voltage_in_mv = pp_clks->data[i].voltage_in_mv; } } +EXPORT_IF_KUNIT(pp_to_dc_clock_levels_with_voltage); + +STATIC_IFN_KUNIT void cap_clock_levels_to_validation( + struct dm_pp_clock_levels *dc_clks, + enum dm_pp_clock_type clk_type, + const struct amd_pp_simple_clock_info *validation_clks) +{ + uint32_t i; + + /* Determine the highest non-boosted level from the Validation Clocks */ + if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks->engine_max_clock) { + /* This clock is higher the validation clock. + * Than means the previous one is the highest + * non-boosted one. + */ + DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { + for (i = 0; i < dc_clks->num_levels; i++) { + if (dc_clks->clocks_in_khz[i] > validation_clks->memory_max_clock) { + DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", + dc_clks->num_levels, i); + dc_clks->num_levels = i > 0 ? i : 1; + break; + } + } + } +} +EXPORT_IF_KUNIT(cap_clock_levels_to_validation); bool dm_pp_get_clock_levels_by_type( const struct dc_context *ctx, @@ -272,7 +306,6 @@ bool dm_pp_get_clock_levels_by_type( struct amdgpu_device *adev = ctx->driver_context; struct amd_pp_clocks pp_clks = { 0 }; struct amd_pp_simple_clock_info validation_clks = { 0 }; - uint32_t i; if (amdgpu_dpm_get_clock_by_type(adev, dc_to_pp_clock_type(clk_type), &pp_clks)) { @@ -300,33 +333,11 @@ bool dm_pp_get_clock_levels_by_type( validation_clks.engine_max_clock *= 10; validation_clks.memory_max_clock *= 10; - /* Determine the highest non-boosted level from the Validation Clocks */ - if (clk_type == DM_PP_CLOCK_TYPE_ENGINE_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.engine_max_clock) { - /* This clock is higher the validation clock. - * Than means the previous one is the highest - * non-boosted one. - */ - DRM_INFO("DM_PPLIB: reducing engine clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } else if (clk_type == DM_PP_CLOCK_TYPE_MEMORY_CLK) { - for (i = 0; i < dc_clks->num_levels; i++) { - if (dc_clks->clocks_in_khz[i] > validation_clks.memory_max_clock) { - DRM_INFO("DM_PPLIB: reducing memory clock level from %d to %d\n", - dc_clks->num_levels, i); - dc_clks->num_levels = i > 0 ? i : 1; - break; - } - } - } + cap_clock_levels_to_validation(dc_clks, clk_type, &validation_clks); return true; } +EXPORT_IF_KUNIT(dm_pp_get_clock_levels_by_type); bool dm_pp_get_clock_levels_by_type_with_latency( const struct dc_context *ctx, @@ -347,6 +358,7 @@ bool dm_pp_get_clock_levels_by_type_with_latency( return true; } +EXPORT_IF_KUNIT(dm_pp_get_clock_levels_by_type_with_latency); bool dm_pp_get_clock_levels_by_type_with_voltage( const struct dc_context *ctx, @@ -367,6 +379,7 @@ bool dm_pp_get_clock_levels_by_type_with_voltage( return true; } +EXPORT_IF_KUNIT(dm_pp_get_clock_levels_by_type_with_voltage); bool dm_pp_notify_wm_clock_changes( const struct dc_context *ctx, @@ -386,6 +399,7 @@ bool dm_pp_notify_wm_clock_changes( return false; } +EXPORT_IF_KUNIT(dm_pp_notify_wm_clock_changes); bool dm_pp_apply_clock_for_voltage_request( const struct dc_context *ctx, @@ -407,26 +421,26 @@ bool dm_pp_apply_clock_for_voltage_request( return true; } +EXPORT_IF_KUNIT(dm_pp_apply_clock_for_voltage_request); -static void pp_rv_set_wm_ranges(struct pp_smu *pp, - struct pp_smu_wm_range_sets *ranges) +STATIC_IFN_KUNIT void build_wm_clock_ranges_soc15( + const struct pp_smu_wm_range_sets *ranges, + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges) { - const struct dc_context *ctx = pp->dm; - struct amdgpu_device *adev = ctx->driver_context; - struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; - struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges; - struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges; + struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = + wm_with_clock_ranges->wm_dmif_clocks_ranges; + struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = + wm_with_clock_ranges->wm_mcif_clocks_ranges; int32_t i; - wm_with_clock_ranges.num_wm_dmif_sets = ranges->num_reader_wm_sets; - wm_with_clock_ranges.num_wm_mcif_sets = ranges->num_writer_wm_sets; + wm_with_clock_ranges->num_wm_dmif_sets = ranges->num_reader_wm_sets; + wm_with_clock_ranges->num_wm_mcif_sets = ranges->num_writer_wm_sets; - for (i = 0; i < wm_with_clock_ranges.num_wm_dmif_sets; i++) { + for (i = 0; i < wm_with_clock_ranges->num_wm_dmif_sets; i++) { if (ranges->reader_wm_sets[i].wm_inst > 3) wm_dce_clocks[i].wm_set_id = WM_SET_A; else - wm_dce_clocks[i].wm_set_id = - ranges->reader_wm_sets[i].wm_inst; + wm_dce_clocks[i].wm_set_id = ranges->reader_wm_sets[i].wm_inst; wm_dce_clocks[i].wm_max_dcfclk_clk_in_khz = ranges->reader_wm_sets[i].max_drain_clk_mhz * 1000; wm_dce_clocks[i].wm_min_dcfclk_clk_in_khz = @@ -437,12 +451,11 @@ static void pp_rv_set_wm_ranges(struct pp_smu *pp, ranges->reader_wm_sets[i].min_fill_clk_mhz * 1000; } - for (i = 0; i < wm_with_clock_ranges.num_wm_mcif_sets; i++) { + for (i = 0; i < wm_with_clock_ranges->num_wm_mcif_sets; i++) { if (ranges->writer_wm_sets[i].wm_inst > 3) wm_soc_clocks[i].wm_set_id = WM_SET_A; else - wm_soc_clocks[i].wm_set_id = - ranges->writer_wm_sets[i].wm_inst; + wm_soc_clocks[i].wm_set_id = ranges->writer_wm_sets[i].wm_inst; wm_soc_clocks[i].wm_max_socclk_clk_in_khz = ranges->writer_wm_sets[i].max_fill_clk_mhz * 1000; wm_soc_clocks[i].wm_min_socclk_clk_in_khz = @@ -452,52 +465,69 @@ static void pp_rv_set_wm_ranges(struct pp_smu *pp, wm_soc_clocks[i].wm_min_mem_clk_in_khz = ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000; } +} +EXPORT_IF_KUNIT(build_wm_clock_ranges_soc15); + +STATIC_IFN_KUNIT void pp_rv_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges) +{ + const struct dc_context *ctx = pp->dm; + struct amdgpu_device *adev = ctx->driver_context; + struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges; + + build_wm_clock_ranges_soc15(ranges, &wm_with_clock_ranges); amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, &wm_with_clock_ranges); } +EXPORT_IF_KUNIT(pp_rv_set_wm_ranges); -static void pp_rv_set_pme_wa_enable(struct pp_smu *pp) +STATIC_IFN_KUNIT void pp_rv_set_pme_wa_enable(struct pp_smu *pp) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; amdgpu_dpm_notify_smu_enable_pwe(adev); } +EXPORT_IF_KUNIT(pp_rv_set_pme_wa_enable); -static void pp_rv_set_active_display_count(struct pp_smu *pp, int count) +STATIC_IFN_KUNIT void pp_rv_set_active_display_count(struct pp_smu *pp, int count) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; amdgpu_dpm_set_active_display_count(adev, count); } +EXPORT_IF_KUNIT(pp_rv_set_active_display_count); -static void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) +STATIC_IFN_KUNIT void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; amdgpu_dpm_set_min_deep_sleep_dcefclk(adev, clock); } +EXPORT_IF_KUNIT(pp_rv_set_min_deep_sleep_dcfclk); -static void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) +STATIC_IFN_KUNIT void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; amdgpu_dpm_set_hard_min_dcefclk_by_freq(adev, clock); } +EXPORT_IF_KUNIT(pp_rv_set_hard_min_dcefclk_by_freq); -static void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) +STATIC_IFN_KUNIT void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; amdgpu_dpm_set_hard_min_fclk_by_freq(adev, mhz); } +EXPORT_IF_KUNIT(pp_rv_set_hard_min_fclk_by_freq); -static enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, struct pp_smu_wm_range_sets *ranges) { const struct dc_context *ctx = pp->dm; @@ -507,8 +537,9 @@ static enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_set_wm_ranges); -static enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count) +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count) { const struct dc_context *ctx = pp->dm; struct amdgpu_device *adev = ctx->driver_context; @@ -523,8 +554,9 @@ static enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count) return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_set_display_count); -static enum pp_smu_status +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int mhz) { const struct dc_context *ctx = pp->dm; @@ -540,8 +572,9 @@ pp_nv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int mhz) return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_set_min_deep_sleep_dcfclk); -static enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq( +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq( struct pp_smu *pp, int mhz) { const struct dc_context *ctx = pp->dm; @@ -563,8 +596,9 @@ static enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq( return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_set_hard_min_dcefclk_by_freq); -static enum pp_smu_status +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz) { const struct dc_context *ctx = pp->dm; @@ -586,8 +620,9 @@ pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz) return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_set_hard_min_uclk_by_freq); -static enum pp_smu_status pp_nv_set_pstate_handshake_support( +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_set_pstate_handshake_support( struct pp_smu *pp, bool pstate_handshake_supported) { const struct dc_context *ctx = pp->dm; @@ -599,8 +634,30 @@ static enum pp_smu_status pp_nv_set_pstate_handshake_support( return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_set_pstate_handshake_support); -static enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, +STATIC_IFN_KUNIT bool pp_smu_nv_clock_id_to_pp(enum pp_smu_nv_clock_id clock_id, + enum amd_pp_clock_type *clock_type) +{ + switch (clock_id) { + case PP_SMU_NV_DISPCLK: + *clock_type = amd_pp_disp_clock; + break; + case PP_SMU_NV_PHYCLK: + *clock_type = amd_pp_phy_clock; + break; + case PP_SMU_NV_PIXELCLK: + *clock_type = amd_pp_pixel_clock; + break; + default: + return false; + } + + return true; +} +EXPORT_IF_KUNIT(pp_smu_nv_clock_id_to_pp); + +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, enum pp_smu_nv_clock_id clock_id, int mhz) { const struct dc_context *ctx = pp->dm; @@ -608,19 +665,9 @@ static enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, struct pp_display_clock_request clock_req; int ret = 0; - switch (clock_id) { - case PP_SMU_NV_DISPCLK: - clock_req.clock_type = amd_pp_disp_clock; - break; - case PP_SMU_NV_PHYCLK: - clock_req.clock_type = amd_pp_phy_clock; - break; - case PP_SMU_NV_PIXELCLK: - clock_req.clock_type = amd_pp_pixel_clock; - break; - default: - break; - } + if (!pp_smu_nv_clock_id_to_pp(clock_id, &clock_req.clock_type)) + return PP_SMU_RESULT_FAIL; + clock_req.clock_freq_in_khz = mhz * 1000; /* 0: successful or smu.ppt_funcs->display_clock_voltage_request = NULL @@ -634,8 +681,9 @@ static enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_set_voltage_by_freq); -static enum pp_smu_status pp_nv_get_maximum_sustainable_clocks( +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_get_maximum_sustainable_clocks( struct pp_smu *pp, struct pp_smu_nv_clock_table *max_clocks) { const struct dc_context *ctx = pp->dm; @@ -651,8 +699,9 @@ static enum pp_smu_status pp_nv_get_maximum_sustainable_clocks( return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_get_maximum_sustainable_clocks); -static enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, +STATIC_IFN_KUNIT enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, unsigned int *clock_values_in_khz, unsigned int *num_states) { const struct dc_context *ctx = pp->dm; @@ -669,8 +718,9 @@ static enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, return PP_SMU_RESULT_OK; } +EXPORT_IF_KUNIT(pp_nv_get_uclk_dpm_states); -static enum pp_smu_status pp_rn_get_dpm_clock_table( +STATIC_IFN_KUNIT enum pp_smu_status pp_rn_get_dpm_clock_table( struct pp_smu *pp, struct dpm_clocks *clock_table) { const struct dc_context *ctx = pp->dm; @@ -685,17 +735,7 @@ static enum pp_smu_status pp_rn_get_dpm_clock_table( return PP_SMU_RESULT_OK; } - -static enum pp_smu_status pp_rn_set_wm_ranges(struct pp_smu *pp, - struct pp_smu_wm_range_sets *ranges) -{ - const struct dc_context *ctx = pp->dm; - struct amdgpu_device *adev = ctx->driver_context; - - amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, ranges); - - return PP_SMU_RESULT_OK; -} +EXPORT_IF_KUNIT(pp_rn_get_dpm_clock_table); void dm_pp_get_funcs( struct dc_context *ctx, @@ -743,7 +783,7 @@ void dm_pp_get_funcs( case DCN_VERSION_2_1: funcs->ctx.ver = PP_SMU_VER_RN; funcs->rn_funcs.pp_smu.dm = ctx; - funcs->rn_funcs.set_wm_ranges = pp_rn_set_wm_ranges; + funcs->rn_funcs.set_wm_ranges = pp_nv_set_wm_ranges; funcs->rn_funcs.get_dpm_clock_table = pp_rn_get_dpm_clock_table; break; default: @@ -751,3 +791,4 @@ void dm_pp_get_funcs( break; } } +EXPORT_IF_KUNIT(dm_pp_get_funcs); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.h new file mode 100644 index 000000000000..f918eb71f0d1 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.h @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#ifndef __AMDGPU_DM_PP_SMU_H__ +#define __AMDGPU_DM_PP_SMU_H__ + +#include "dm_pp_interface.h" + +struct amd_pp_display_configuration; +struct pp_smu_wm_range_sets; +struct dm_pp_wm_sets_with_clock_ranges_soc15; + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +void build_pm_display_cfg(struct amd_pp_display_configuration *pm_display_cfg, + const struct dm_pp_display_configuration *pp_display_cfg); +void build_wm_clock_ranges_soc15(const struct pp_smu_wm_range_sets *ranges, + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges); +void get_default_clock_levels(enum dm_pp_clock_type clk_type, struct dm_pp_clock_levels *clks); +enum amd_pp_clock_type dc_to_pp_clock_type(enum dm_pp_clock_type dm_pp_clk_type); +void pp_to_dc_clock_levels(const struct amd_pp_clocks *pp_clks, + struct dm_pp_clock_levels *dc_clks, + enum dm_pp_clock_type dc_clk_type); +void pp_to_dc_clock_levels_with_latency(const struct pp_clock_levels_with_latency *pp_clks, + struct dm_pp_clock_levels_with_latency *clk_level_info, + enum dm_pp_clock_type dc_clk_type); +void pp_to_dc_clock_levels_with_voltage(const struct pp_clock_levels_with_voltage *pp_clks, + struct dm_pp_clock_levels_with_voltage *clk_level_info, + enum dm_pp_clock_type dc_clk_type); +void cap_clock_levels_to_validation(struct dm_pp_clock_levels *dc_clks, + enum dm_pp_clock_type clk_type, + const struct amd_pp_simple_clock_info *validation_clks); +bool pp_smu_nv_clock_id_to_pp(enum pp_smu_nv_clock_id clock_id, + enum amd_pp_clock_type *clock_type); +void pp_rv_set_wm_ranges(struct pp_smu *pp, struct pp_smu_wm_range_sets *ranges); +void pp_rv_set_pme_wa_enable(struct pp_smu *pp); +void pp_rv_set_active_display_count(struct pp_smu *pp, int count); +void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock); +void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock); +void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz); +enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp, + struct pp_smu_wm_range_sets *ranges); +enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count); +enum pp_smu_status pp_nv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int mhz); +enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int mhz); +enum pp_smu_status pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz); +enum pp_smu_status pp_nv_set_pstate_handshake_support(struct pp_smu *pp, + bool pstate_handshake_supported); +enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp, + enum pp_smu_nv_clock_id clock_id, int mhz); +enum pp_smu_status pp_nv_get_maximum_sustainable_clocks(struct pp_smu *pp, + struct pp_smu_nv_clock_table *max_clocks); +enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp, + unsigned int *clock_values_in_khz, + unsigned int *num_states); +enum pp_smu_status pp_rn_get_dpm_clock_table(struct pp_smu *pp, + struct dpm_clocks *clock_table); +#endif + +#endif /* __AMDGPU_DM_PP_SMU_H__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c index 0dadc0bb214f..f87de3d18ac0 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c @@ -32,8 +32,8 @@ #include "modules/power/power_helpers.h" #include "amdgpu_dm_kunit_helpers.h" - -static bool link_supports_psrsu(struct dc_link *link) +STATIC_IFN_KUNIT +bool link_supports_psrsu(struct dc_link *link) { struct dc *dc = link->ctx->dc; @@ -60,6 +60,7 @@ static bool link_supports_psrsu(struct dc_link *link) /* Temporarily disable PSR-SU to avoid glitches */ return false; } +EXPORT_IF_KUNIT(link_supports_psrsu); STATIC_IFN_KUNIT void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps) @@ -134,6 +135,7 @@ bool amdgpu_dm_set_psr_caps(struct dc_link *link, struct amdgpu_dm_connector *ac amdgpu_dm_psr_fill_caps(link, &aconnector->psr_caps); return true; } +EXPORT_IF_KUNIT(amdgpu_dm_set_psr_caps); /* * amdgpu_dm_psr_is_active_allowed() - check if psr is allowed on any stream @@ -157,6 +159,7 @@ bool amdgpu_dm_psr_is_active_allowed(struct amdgpu_display_manager *dm) } return false; } +EXPORT_IF_KUNIT(amdgpu_dm_psr_is_active_allowed); /* * amdgpu_dm_psr_set_event() - set or clear PSR event for stream @@ -190,3 +193,47 @@ bool amdgpu_dm_psr_set_event(struct amdgpu_display_manager *dm, struct dc_stream set_event, event, wait_for_disable); } EXPORT_IF_KUNIT(amdgpu_dm_psr_set_event); + +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +/** + * amdgpu_dm_psr_get_dc_feature_mask() - Get DC feature mask for KUnit tests. + * + * Return: Current value of amdgpu_dc_feature_mask. + */ +unsigned int amdgpu_dm_psr_get_dc_feature_mask(void) +{ + return amdgpu_dc_feature_mask; +} +EXPORT_IF_KUNIT(amdgpu_dm_psr_get_dc_feature_mask); + +/** + * amdgpu_dm_psr_set_dc_feature_mask() - Set DC feature mask for KUnit tests. + * @feature_mask: DC feature mask to set while testing amdgpu_dm_psr_fill_caps(). + */ +void amdgpu_dm_psr_set_dc_feature_mask(unsigned int feature_mask) +{ + amdgpu_dc_feature_mask = feature_mask; +} +EXPORT_IF_KUNIT(amdgpu_dm_psr_set_dc_feature_mask); + +/** + * amdgpu_dm_psr_get_dc_debug_mask() - Get DC debug mask for KUnit tests. + * + * Return: Current value of amdgpu_dc_debug_mask. + */ +unsigned int amdgpu_dm_psr_get_dc_debug_mask(void) +{ + return amdgpu_dc_debug_mask; +} +EXPORT_IF_KUNIT(amdgpu_dm_psr_get_dc_debug_mask); + +/** + * amdgpu_dm_psr_set_dc_debug_mask() - Set DC debug mask for KUnit tests. + * @debug_mask: DC debug mask to set while testing link_supports_psrsu(). + */ +void amdgpu_dm_psr_set_dc_debug_mask(unsigned int debug_mask) +{ + amdgpu_dc_debug_mask = debug_mask; +} +EXPORT_IF_KUNIT(amdgpu_dm_psr_set_dc_debug_mask); +#endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h index 40a09b5dc606..e442e7ed82ec 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.h @@ -43,7 +43,12 @@ bool amdgpu_dm_psr_set_event(struct amdgpu_display_manager *dm, bool wait_for_disable); #if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +bool link_supports_psrsu(struct dc_link *link); void amdgpu_dm_psr_fill_caps(struct dc_link *link, struct psr_caps *caps); +unsigned int amdgpu_dm_psr_get_dc_feature_mask(void); +void amdgpu_dm_psr_set_dc_feature_mask(unsigned int feature_mask); +unsigned int amdgpu_dm_psr_get_dc_debug_mask(void); +void amdgpu_dm_psr_set_dc_debug_mask(unsigned int debug_mask); #endif #endif /* AMDGPU_DM_AMDGPU_DM_PSR_H_ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c index 1da07ebf9217..cf28d50c3b5e 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_quirks.c @@ -28,6 +28,7 @@ #include "amdgpu.h" #include "amdgpu_dm.h" +#include "amdgpu_dm_kunit_helpers.h" struct amdgpu_dm_quirks { bool aux_hpd_discon; @@ -176,3 +177,4 @@ void retrieve_dmi_info(struct amdgpu_display_manager *dm) drm_info(dev, "support_edp0_on_dp1 attached\n"); } } +EXPORT_IF_KUNIT(retrieve_dmi_info); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c index 22aa4305d2af..42e17119461d 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_replay.c @@ -121,14 +121,14 @@ bool amdgpu_dm_set_replay_caps(struct dc_link *link, struct amdgpu_dm_connector debug_flags = (union replay_debug_flags *)&pr_config.debug_flags; debug_flags->u32All = 0; - debug_flags->bitfields.visual_confirm = - link->ctx->dc->debug.visual_confirm == VISUAL_CONFIRM_REPLAY; + debug_flags->bitfields.visual_confirm = dc->debug.visual_confirm == VISUAL_CONFIRM_REPLAY; debug_flags->bitfields.skip_crtc_disabled = dc->debug.replay_skip_crtc_disabled; init_replay_config(link, &pr_config); return true; } +EXPORT_IF_KUNIT(amdgpu_dm_set_replay_caps); /* * amdgpu_dm_link_setup_replay() - config replay settings @@ -144,7 +144,6 @@ bool amdgpu_dm_link_setup_replay(struct dc_stream_state *stream, { struct dc_link *link; unsigned int static_coasting_vtotal; - unsigned int nom_coasting_vtotal; if (!stream || !stream->link || !vrr_params) return false; @@ -159,16 +158,16 @@ bool amdgpu_dm_link_setup_replay(struct dc_stream_state *stream, calculate_replay_link_off_frame_count(link, stream->timing.v_total, stream->timing.h_total); - nom_coasting_vtotal = stream->timing.v_total; static_coasting_vtotal = mod_freesync_calc_v_total_from_refresh(stream, vrr_params->min_refresh_in_uhz); set_replay_coasting_vtotal(link, PR_COASTING_TYPE_NOM, - nom_coasting_vtotal); + stream->timing.v_total); set_replay_coasting_vtotal(link, PR_COASTING_TYPE_STATIC, static_coasting_vtotal); return true; } +EXPORT_IF_KUNIT(amdgpu_dm_link_setup_replay); /* * amdgpu_dm_replay_set_event() - set or clear replay event for a stream @@ -208,3 +207,4 @@ bool amdgpu_dm_replay_set_event(struct amdgpu_display_manager *dm, return mod_power_set_replay_event(dm->power_module, stream, set_event, event, wait_for_disable); } +EXPORT_IF_KUNIT(amdgpu_dm_replay_set_event); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 84dcb573d98f..6c0464754ed8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -32,9 +32,11 @@ #include "dm_services.h" #include "amdgpu.h" #include "amdgpu_dm.h" +#include "amdgpu_dm_backlight.h" #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" #include "amdgpu_dm_trace.h" +#include "amdgpu_dm_kunit_helpers.h" unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, @@ -43,6 +45,7 @@ { return current_time_stamp - last_time_stamp; } +EXPORT_IF_KUNIT(dm_get_elapse_time_in_ns); void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc_context *ctx) { @@ -52,14 +55,17 @@ void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc &ctx->perf_trace->last_entry_write, func_name, line); } +EXPORT_IF_KUNIT(dm_perf_trace_timestamp); void dm_trace_smu_enter(uint32_t msg_id, uint32_t param_in, unsigned int delay, struct dc_context *ctx) { } +EXPORT_IF_KUNIT(dm_trace_smu_enter); void dm_trace_smu_exit(bool success, uint32_t response, struct dc_context *ctx) { } +EXPORT_IF_KUNIT(dm_trace_smu_exit); /**** power component interfaces ****/ @@ -89,3 +95,4 @@ bool dm_query_extended_brightness_caps(struct dc_context *ctx, sizeof(struct dm_bl_data_point) * pCaps->num_data_points); return true; } +EXPORT_IF_KUNIT(dm_query_extended_brightness_caps); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c index 110f0173eee6..0bf82e46f773 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.c @@ -29,6 +29,7 @@ #include "amdgpu.h" #include "amdgpu_dm.h" #include "amdgpu_dm_wb.h" +#include "amdgpu_dm_kunit_helpers.h" #include "amdgpu_display.h" #include "dc.h" @@ -40,7 +41,7 @@ static const u32 amdgpu_dm_wb_formats[] = { DRM_FORMAT_XRGB2101010, }; -static int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder, +STATIC_IFN_KUNIT int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { @@ -59,9 +60,11 @@ static int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder, return -EINVAL; } - for (i = 0; i < sizeof(amdgpu_dm_wb_formats) / sizeof(u32); i++) { - if (fb->format->format == amdgpu_dm_wb_formats[i]) + for (i = 0; i < ARRAY_SIZE(amdgpu_dm_wb_formats); i++) { + if (fb->format->format == amdgpu_dm_wb_formats[i]) { found = true; + break; + } } if (!found) { @@ -72,13 +75,15 @@ static int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder, return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_wb_encoder_atomic_check); -static int amdgpu_dm_wb_connector_get_modes(struct drm_connector *connector) +STATIC_IFN_KUNIT int amdgpu_dm_wb_connector_get_modes(struct drm_connector *connector) { /* Maximum resolution supported by DWB */ return drm_add_modes_noedid(connector, 3840, 2160); } +EXPORT_IF_KUNIT(amdgpu_dm_wb_connector_get_modes); static int amdgpu_dm_wb_prepare_job(struct drm_writeback_connector *wb_connector, struct drm_writeback_job *job) @@ -187,7 +192,7 @@ int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, { struct dc *dc = dm->dc; struct dc_link *link = dc_get_link_at_index(dc, link_index); - int res = 0; + int res; wbcon->link = link; @@ -211,3 +216,4 @@ int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, return 0; } +EXPORT_IF_KUNIT(amdgpu_dm_wb_connector_init); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h index 13d31c857dee..7e9fd7a036fa 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_wb.h @@ -29,8 +29,21 @@ #include +struct amdgpu_display_manager; +struct amdgpu_dm_wb_connector; + int amdgpu_dm_wb_connector_init(struct amdgpu_display_manager *dm, struct amdgpu_dm_wb_connector *dm_wbcon, uint32_t link_index); +#if IS_ENABLED(CONFIG_DRM_AMD_DC_KUNIT_TEST) +#include +#include + +int amdgpu_dm_wb_encoder_atomic_check(struct drm_encoder *encoder, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); +int amdgpu_dm_wb_connector_get_modes(struct drm_connector *connector); +#endif + #endif diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig index bd1bf8d959f9..c7c8527dbb10 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/.kunitconfig @@ -15,6 +15,12 @@ CONFIG_I2C=y CONFIG_POWER_SUPPLY=y CONFIG_CRC16=y +# Limit stack size to 1280 +CONFIG_FRAME_WARN=1280 + +# Treat warnings as errors +CONFIG_WERROR=y + # GCOV Coverage - see tools/testing/kunit/configs/coverage_uml.config CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_INFO=y diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile index 768f9bbc50e1..1592e8dae1a9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile @@ -8,11 +8,29 @@ ccflags-y += -I$(src)/../../include ccflags-y += -I$(src)/../../modules/inc ccflags-y += -I$(src)/../../dc ccflags-y += -I$(src)/../../../amdgpu +ccflags-y += -I$(src)/../../../amdkfd +ccflags-y += -I$(src)/../../../include +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_kunit_helpers.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crc_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_hdcp_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_audio_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_color_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_colorop_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_connector_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_backlight_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_dmub_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_psr_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_replay_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_ism_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_irq_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_wb_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_plane_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_mst_types_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_pp_smu_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crtc_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_services_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_helpers_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_quirks_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_plane_test.o diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c new file mode 100644 index 000000000000..79ff5d9b3fa5 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_audio_test.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_audio.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include + +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_audio.h" + +/* Tests for amdgpu_dm_audio_init() */ + +/** + * dm_test_audio_init_disabled - Test audio init exits when audio is disabled + * @test: The KUnit test context + */ +static void dm_test_audio_init_disabled(struct kunit *test) +{ + struct amdgpu_device *adev; + int saved_audio = amdgpu_dm_audio_get_param(); + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + amdgpu_dm_audio_set_param(0); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_audio_init(adev), 0); + KUNIT_EXPECT_FALSE(test, adev->mode_info.audio.enabled); + KUNIT_EXPECT_FALSE(test, adev->dm.audio_registered); + + amdgpu_dm_audio_set_param(saved_audio); +} + +/* Tests for amdgpu_dm_audio_fini() */ + +/** + * dm_test_audio_fini_without_enabled_audio - Test fini exits when audio is not enabled + * @test: The KUnit test context + */ +static void dm_test_audio_fini_without_enabled_audio(struct kunit *test) +{ + struct amdgpu_device *adev; + int saved_audio = amdgpu_dm_audio_get_param(); + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + amdgpu_dm_audio_set_param(1); + adev->mode_info.audio.enabled = false; + adev->dm.audio_registered = true; + + amdgpu_dm_audio_fini(adev); + + KUNIT_EXPECT_FALSE(test, adev->mode_info.audio.enabled); + KUNIT_EXPECT_TRUE(test, adev->dm.audio_registered); + + amdgpu_dm_audio_set_param(saved_audio); +} + +/* Tests for amdgpu_dm_fill_audio_info() */ + +/** + * dm_test_fill_audio_info_ids_name_flags - Test Fill audio info ids name flags + * @test: The KUnit test context + */ +static void dm_test_fill_audio_info_ids_name_flags(struct kunit *test) +{ + struct audio_info *audio_info; + struct drm_connector *connector; + struct dc_sink *dc_sink; + const char *name = "DM-AUDIO-PANEL"; + + audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + + dc_sink->edid_caps.manufacturer_id = 0x1234; + dc_sink->edid_caps.product_id = 0xABCD; + dc_sink->edid_caps.speaker_flags = 0x5; + strscpy(dc_sink->edid_caps.display_name, name, + AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS); + + connector->display_info.cea_rev = 1; + + amdgpu_dm_fill_audio_info(audio_info, connector, dc_sink); + + KUNIT_EXPECT_EQ(test, audio_info->manufacture_id, 0x1234U); + KUNIT_EXPECT_EQ(test, audio_info->product_id, 0xABCDU); + KUNIT_EXPECT_EQ(test, audio_info->flags.all, 0x5U); + KUNIT_EXPECT_STREQ(test, audio_info->display_name, name); +} + +/** + * dm_test_fill_audio_info_cea_lt_3_skips_modes - Test Fill audio info cea lt 3 skips modes + * @test: The KUnit test context + */ +static void dm_test_fill_audio_info_cea_lt_3_skips_modes(struct kunit *test) +{ + struct audio_info *audio_info; + struct drm_connector *connector; + struct dc_sink *dc_sink; + + audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + + connector->display_info.cea_rev = 2; + dc_sink->edid_caps.audio_mode_count = 2; + dc_sink->edid_caps.audio_modes[0].format_code = 1; + dc_sink->edid_caps.audio_modes[0].channel_count = 2; + dc_sink->edid_caps.audio_modes[0].sample_rate = 0x07; + dc_sink->edid_caps.audio_modes[0].sample_size = 16; + + amdgpu_dm_fill_audio_info(audio_info, connector, dc_sink); + + KUNIT_EXPECT_EQ(test, audio_info->mode_count, 0U); +} + +/** + * dm_test_fill_audio_info_cea_ge_3_copies_modes - Test Fill audio info cea ge 3 copies modes + * @test: The KUnit test context + */ +static void dm_test_fill_audio_info_cea_ge_3_copies_modes(struct kunit *test) +{ + struct audio_info *audio_info; + struct drm_connector *connector; + struct dc_sink *dc_sink; + + audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + + connector->display_info.cea_rev = 3; + dc_sink->edid_caps.audio_mode_count = 2; + + dc_sink->edid_caps.audio_modes[0].format_code = 1; + dc_sink->edid_caps.audio_modes[0].channel_count = 2; + dc_sink->edid_caps.audio_modes[0].sample_rate = 0x07; + dc_sink->edid_caps.audio_modes[0].sample_size = 16; + + dc_sink->edid_caps.audio_modes[1].format_code = 11; + dc_sink->edid_caps.audio_modes[1].channel_count = 6; + dc_sink->edid_caps.audio_modes[1].sample_rate = 0x1F; + dc_sink->edid_caps.audio_modes[1].sample_size = 24; + + amdgpu_dm_fill_audio_info(audio_info, connector, dc_sink); + + KUNIT_EXPECT_EQ(test, audio_info->mode_count, 2U); + + KUNIT_EXPECT_EQ(test, (int)audio_info->modes[0].format_code, 1); + KUNIT_EXPECT_EQ(test, audio_info->modes[0].channel_count, 2); + KUNIT_EXPECT_EQ(test, audio_info->modes[0].sample_rates.all, 0x07U); + KUNIT_EXPECT_EQ(test, audio_info->modes[0].sample_size, 16); + + KUNIT_EXPECT_EQ(test, (int)audio_info->modes[1].format_code, 11); + KUNIT_EXPECT_EQ(test, audio_info->modes[1].channel_count, 6); + KUNIT_EXPECT_EQ(test, audio_info->modes[1].sample_rates.all, 0x1FU); + KUNIT_EXPECT_EQ(test, audio_info->modes[1].sample_size, 24); +} + +/** + * dm_test_fill_audio_info_latency_present - Test Fill audio info latency present + * @test: The KUnit test context + */ +static void dm_test_fill_audio_info_latency_present(struct kunit *test) +{ + struct audio_info *audio_info; + struct drm_connector *connector; + struct dc_sink *dc_sink; + + audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + + connector->display_info.cea_rev = 3; + connector->latency_present[0] = true; + connector->video_latency[0] = 11; + connector->audio_latency[0] = 22; + + amdgpu_dm_fill_audio_info(audio_info, connector, dc_sink); + + KUNIT_EXPECT_EQ(test, audio_info->video_latency, 11U); + KUNIT_EXPECT_EQ(test, audio_info->audio_latency, 22U); +} + +/** + * dm_test_fill_audio_info_latency_absent_keeps_zero - Test Fill audio info latency absent keeps zero + * @test: The KUnit test context + */ +static void dm_test_fill_audio_info_latency_absent_keeps_zero(struct kunit *test) +{ + struct audio_info *audio_info; + struct drm_connector *connector; + struct dc_sink *dc_sink; + + audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + + connector->display_info.cea_rev = 3; + connector->latency_present[0] = false; + connector->video_latency[0] = 99; + connector->audio_latency[0] = 88; + + amdgpu_dm_fill_audio_info(audio_info, connector, dc_sink); + + KUNIT_EXPECT_EQ(test, audio_info->video_latency, 0U); + KUNIT_EXPECT_EQ(test, audio_info->audio_latency, 0U); +} + +/** + * dm_test_fill_audio_info_cea_ge_3_zero_modes - Test cea >= 3 with zero modes + * @test: The KUnit test context + * + * When cea_rev >= 3 but the sink reports no audio modes, mode_count must be + * copied as 0 and no mode entries should be populated. + */ +static void dm_test_fill_audio_info_cea_ge_3_zero_modes(struct kunit *test) +{ + struct audio_info *audio_info; + struct drm_connector *connector; + struct dc_sink *dc_sink; + + audio_info = kunit_kzalloc(test, sizeof(*audio_info), GFP_KERNEL); + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + dc_sink = kunit_kzalloc(test, sizeof(*dc_sink), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_info); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc_sink); + + connector->display_info.cea_rev = 3; + dc_sink->edid_caps.audio_mode_count = 0; + + amdgpu_dm_fill_audio_info(audio_info, connector, dc_sink); + + KUNIT_EXPECT_EQ(test, audio_info->mode_count, 0U); + KUNIT_EXPECT_EQ(test, (int)audio_info->modes[0].format_code, 0); +} + +/* Tests for amdgpu_dm_audio_component_bind()/unbind() */ + +/** + * dm_test_audio_component_bind_sets_fields - Test bind wires up audio component + * @test: The KUnit test context + * + * Binding must publish the DRM audio component ops, record the kernel device, + * and store the component pointer in the display manager. + */ +static void dm_test_audio_component_bind_sets_fields(struct kunit *test) +{ + struct amdgpu_device *adev; + struct device *kdev; + struct drm_audio_component *acomp; + int ret; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + kdev = kunit_kzalloc(test, sizeof(*kdev), GFP_KERNEL); + acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, kdev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + + dev_set_drvdata(kdev, &adev->ddev); + + ret = amdgpu_dm_audio_component_bind(kdev, NULL, acomp); + + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_NOT_NULL(test, acomp->ops); + KUNIT_EXPECT_PTR_EQ(test, acomp->dev, kdev); + KUNIT_EXPECT_PTR_EQ(test, adev->dm.audio_component, acomp); +} + +/** + * dm_test_audio_component_unbind_clears_fields - Test unbind tears down component + * @test: The KUnit test context + * + * Unbinding must clear the component ops, the kernel device, and the display + * manager's stored component pointer. + */ +static void dm_test_audio_component_unbind_clears_fields(struct kunit *test) +{ + struct amdgpu_device *adev; + struct device *kdev; + struct drm_audio_component *acomp; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + kdev = kunit_kzalloc(test, sizeof(*kdev), GFP_KERNEL); + acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, kdev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + + dev_set_drvdata(kdev, &adev->ddev); + + /* Pretend a prior bind already happened. */ + acomp->dev = kdev; + adev->dm.audio_component = acomp; + + amdgpu_dm_audio_component_unbind(kdev, NULL, acomp); + + KUNIT_EXPECT_NULL(test, acomp->ops); + KUNIT_EXPECT_NULL(test, acomp->dev); + KUNIT_EXPECT_NULL(test, adev->dm.audio_component); +} + +/* Tests for amdgpu_dm_audio_eld_notify() */ + +static int dm_test_eld_notify_count; +static int dm_test_eld_notify_port; +static void *dm_test_eld_notify_ptr; + +static void dm_test_pin_eld_notify(void *audio_ptr, int port, int pipe) +{ + dm_test_eld_notify_count++; + dm_test_eld_notify_port = port; + dm_test_eld_notify_ptr = audio_ptr; +} + +/** + * dm_test_eld_notify_invokes_callback - Test ELD notify forwards to hda driver + * @test: The KUnit test context + * + * When a component with a pin_eld_notify callback is registered, the notify + * helper must invoke it with the audio pointer and the requested pin. + */ +static void dm_test_eld_notify_invokes_callback(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_audio_component *acomp; + struct drm_audio_component_audio_ops *audio_ops; + int marker = 0; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); + audio_ops = kunit_kzalloc(test, sizeof(*audio_ops), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_ops); + + audio_ops->audio_ptr = ▮ + audio_ops->pin_eld_notify = dm_test_pin_eld_notify; + acomp->audio_ops = audio_ops; + adev->dm.audio_component = acomp; + + dm_test_eld_notify_count = 0; + dm_test_eld_notify_port = -100; + dm_test_eld_notify_ptr = NULL; + + amdgpu_dm_audio_eld_notify(adev, 7); + + KUNIT_EXPECT_EQ(test, dm_test_eld_notify_count, 1); + KUNIT_EXPECT_EQ(test, dm_test_eld_notify_port, 7); + KUNIT_EXPECT_PTR_EQ(test, dm_test_eld_notify_ptr, (void *)&marker); +} + +/** + * dm_test_eld_notify_no_component - Test ELD notify is a no-op without component + * @test: The KUnit test context + * + * With no registered audio component, the notify helper must return without + * invoking any callback. + */ +static void dm_test_eld_notify_no_component(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->dm.audio_component = NULL; + + dm_test_eld_notify_count = 0; + + amdgpu_dm_audio_eld_notify(adev, 3); + + KUNIT_EXPECT_EQ(test, dm_test_eld_notify_count, 0); +} + +/** + * dm_test_eld_notify_null_audio_ops - Test ELD notify is a no-op without audio_ops + * @test: The KUnit test context + * + * A component without audio_ops must not trigger any callback. + */ +static void dm_test_eld_notify_null_audio_ops(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_audio_component *acomp; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + + acomp->audio_ops = NULL; + adev->dm.audio_component = acomp; + + dm_test_eld_notify_count = 0; + + amdgpu_dm_audio_eld_notify(adev, 3); + + KUNIT_EXPECT_EQ(test, dm_test_eld_notify_count, 0); +} + +/** + * dm_test_eld_notify_null_callback - Test ELD notify is a no-op without callback + * @test: The KUnit test context + * + * audio_ops present but with a NULL pin_eld_notify must not crash or call + * anything. + */ +static void dm_test_eld_notify_null_callback(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_audio_component *acomp; + struct drm_audio_component_audio_ops *audio_ops; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + acomp = kunit_kzalloc(test, sizeof(*acomp), GFP_KERNEL); + audio_ops = kunit_kzalloc(test, sizeof(*audio_ops), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acomp); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, audio_ops); + + audio_ops->pin_eld_notify = NULL; + acomp->audio_ops = audio_ops; + adev->dm.audio_component = acomp; + + dm_test_eld_notify_count = 0; + + amdgpu_dm_audio_eld_notify(adev, 3); + + KUNIT_EXPECT_EQ(test, dm_test_eld_notify_count, 0); +} + +static struct kunit_case dm_audio_test_cases[] = { + /* amdgpu_dm_audio_init */ + KUNIT_CASE(dm_test_audio_init_disabled), + /* amdgpu_dm_audio_fini */ + KUNIT_CASE(dm_test_audio_fini_without_enabled_audio), + /* amdgpu_dm_fill_audio_info */ + KUNIT_CASE(dm_test_fill_audio_info_ids_name_flags), + KUNIT_CASE(dm_test_fill_audio_info_cea_lt_3_skips_modes), + KUNIT_CASE(dm_test_fill_audio_info_cea_ge_3_copies_modes), + KUNIT_CASE(dm_test_fill_audio_info_cea_ge_3_zero_modes), + KUNIT_CASE(dm_test_fill_audio_info_latency_present), + KUNIT_CASE(dm_test_fill_audio_info_latency_absent_keeps_zero), + /* amdgpu_dm_audio_component_bind/unbind */ + KUNIT_CASE(dm_test_audio_component_bind_sets_fields), + KUNIT_CASE(dm_test_audio_component_unbind_clears_fields), + /* amdgpu_dm_audio_eld_notify */ + KUNIT_CASE(dm_test_eld_notify_invokes_callback), + KUNIT_CASE(dm_test_eld_notify_no_component), + KUNIT_CASE(dm_test_eld_notify_null_audio_ops), + KUNIT_CASE(dm_test_eld_notify_null_callback), + {} +}; + +static struct kunit_suite dm_audio_test_suite = { + .name = "amdgpu_dm_audio", + .test_cases = dm_audio_test_cases, +}; + +kunit_test_suite(dm_audio_test_suite); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_audio"); +MODULE_AUTHOR("AMD"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c new file mode 100644 index 000000000000..fff50c1325c6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c @@ -0,0 +1,1242 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_backlight.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_backlight.h" +#include "amdgpu_dm_kunit_test_helpers.h" +#include "amd_shared.h" +#include "dc/inc/hw/panel_cntl.h" + +struct dm_backlight_connector_fixture { + struct amdgpu_device *adev; + struct amdgpu_dm_connector *aconnector; + struct dc_link *link; +}; + +static void setup_test_connector(struct kunit *test, + struct dm_backlight_connector_fixture *fixture, + int bl_idx, enum signal_type signal) +{ + fixture->adev = kunit_kzalloc(test, sizeof(*fixture->adev), GFP_KERNEL); + fixture->aconnector = kunit_kzalloc(test, sizeof(*fixture->aconnector), GFP_KERNEL); + fixture->link = kunit_kzalloc(test, sizeof(*fixture->link), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->aconnector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fixture->link); + + fixture->aconnector->bl_idx = bl_idx; + fixture->aconnector->dc_link = fixture->link; + fixture->aconnector->base.dev = &fixture->adev->ddev; + fixture->link->connector_signal = signal; +} + +/* Tests for amdgpu_dm_backlight_get_device_index() */ + +/** + * dm_test_backlight_device_index_matches_second - Test matching second backlight device + * @test: The KUnit test context + */ +static void dm_test_backlight_device_index_matches_second(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct backlight_device *bd0; + struct backlight_device *bd1; + + bd0 = kunit_kzalloc(test, sizeof(*bd0), GFP_KERNEL); + bd1 = kunit_kzalloc(test, sizeof(*bd1), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, bd0); + KUNIT_ASSERT_NOT_NULL(test, bd1); + + dm->num_of_edps = 2; + dm->backlight_dev[0] = bd0; + dm->backlight_dev[1] = bd1; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_backlight_get_device_index(dm, bd1), 1); +} + +/** + * dm_test_backlight_device_index_missing_fallback - Test missing backlight device fallback + * @test: The KUnit test context + */ +static void dm_test_backlight_device_index_missing_fallback(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct backlight_device *known_bd; + struct backlight_device *unknown_bd; + + known_bd = kunit_kzalloc(test, sizeof(*known_bd), GFP_KERNEL); + unknown_bd = kunit_kzalloc(test, sizeof(*unknown_bd), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, known_bd); + KUNIT_ASSERT_NOT_NULL(test, unknown_bd); + + dm->num_of_edps = 1; + dm->backlight_dev[0] = known_bd; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_backlight_get_device_index(dm, unknown_bd), 0); +} + +/* Tests for amdgpu_dm_update_backlight_caps() */ + +/** + * dm_test_backlight_caps_valid_short_circuit - Test Backlight caps valid short circuit + * @test: The KUnit test context + */ +static void dm_test_backlight_caps_valid_short_circuit(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[0]; + + caps->caps_valid = true; + caps->aux_support = false; + caps->min_input_signal = 42; + caps->max_input_signal = 199; + + amdgpu_dm_update_backlight_caps(dm, 0); + + KUNIT_EXPECT_TRUE(test, caps->caps_valid); + KUNIT_EXPECT_EQ(test, caps->min_input_signal, 42); + KUNIT_EXPECT_EQ(test, caps->max_input_signal, 199); +} + +#if !defined(CONFIG_ACPI) + +/** + * dm_test_backlight_caps_aux_support_noop - Test Backlight caps aux support noop + * @test: The KUnit test context + */ +static void dm_test_backlight_caps_aux_support_noop(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[0]; + + caps->caps_valid = false; + caps->aux_support = true; + caps->min_input_signal = 11; + caps->max_input_signal = 222; + + amdgpu_dm_update_backlight_caps(dm, 0); + + KUNIT_EXPECT_FALSE(test, caps->caps_valid); + KUNIT_EXPECT_EQ(test, caps->min_input_signal, 11); + KUNIT_EXPECT_EQ(test, caps->max_input_signal, 222); +} + +/** + * dm_test_backlight_caps_non_aux_sets_defaults - Test Backlight caps non aux sets defaults + * @test: The KUnit test context + */ +static void dm_test_backlight_caps_non_aux_sets_defaults(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct amdgpu_dm_backlight_caps *caps = &dm->backlight_caps[0]; + + caps->caps_valid = false; + caps->aux_support = false; + caps->min_input_signal = 0; + caps->max_input_signal = 0; + + amdgpu_dm_update_backlight_caps(dm, 0); + + KUNIT_EXPECT_TRUE(test, caps->caps_valid); + KUNIT_EXPECT_EQ(test, caps->min_input_signal, AMDGPU_DM_DEFAULT_MIN_BACKLIGHT); + KUNIT_EXPECT_EQ(test, caps->max_input_signal, AMDGPU_DM_DEFAULT_MAX_BACKLIGHT); +} +#endif + +/* Tests for get_brightness_range() */ + +/** + * dm_test_brightness_range_null_caps - Test Brightness range null caps + * @test: The KUnit test context + */ +static void dm_test_brightness_range_null_caps(struct kunit *test) +{ + unsigned int min = 99, max = 99; + + KUNIT_EXPECT_EQ(test, get_brightness_range(NULL, &min, &max), 0); + /* min/max should remain untouched */ + KUNIT_EXPECT_EQ(test, min, 99U); + KUNIT_EXPECT_EQ(test, max, 99U); +} + +/** + * dm_test_brightness_range_pwm - Test Brightness range pwm + * @test: The KUnit test context + */ +static void dm_test_brightness_range_pwm(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + + KUNIT_EXPECT_EQ(test, get_brightness_range(&caps, &min, &max), 1); + /* 0x101 * AMDGPU_DM_DEFAULT_MIN_BACKLIGHT, 0x101 * AMDGPU_DM_DEFAULT_MAX_BACKLIGHT */ + KUNIT_EXPECT_EQ(test, min, 0x101U * AMDGPU_DM_DEFAULT_MIN_BACKLIGHT); + KUNIT_EXPECT_EQ(test, max, 0x101U * AMDGPU_DM_DEFAULT_MAX_BACKLIGHT); +} + +/** + * dm_test_brightness_range_aux - Test Brightness range aux + * @test: The KUnit test context + */ +static void dm_test_brightness_range_aux(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.aux_support = true; + caps.aux_min_input_signal = 1; + caps.aux_max_input_signal = 512; + + KUNIT_EXPECT_EQ(test, get_brightness_range(&caps, &min, &max), 1); + /* millinits: 1000 * value */ + KUNIT_EXPECT_EQ(test, min, 1000U); + KUNIT_EXPECT_EQ(test, max, 512000U); +} + +/* Tests for convert_brightness_to_user() */ + +/** + * dm_test_brightness_to_user_null_caps - Test Brightness to user null caps + * @test: The KUnit test context + */ +static void dm_test_brightness_to_user_null_caps(struct kunit *test) +{ + /* + * With NULL caps, get_brightness_range fails → passthrough. + * We simulate this by passing a zeroed caps struct where + * max_input_signal=0 makes max=0 and the function hits + * get_brightness_range returning 0 since caps is NULL. + */ + KUNIT_EXPECT_EQ(test, convert_brightness_to_user(NULL, 42), 42U); +} + +/** + * dm_test_brightness_to_user_below_min - Test Brightness to user below min + * @test: The KUnit test context + */ +static void dm_test_brightness_to_user_below_min(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + + /* brightness < min (0x101*AMDGPU_DM_DEFAULT_MIN_BACKLIGHT), should return 0 */ + KUNIT_EXPECT_EQ(test, convert_brightness_to_user(&caps, 100), 0U); +} + +/** + * dm_test_brightness_to_user_at_max - Test Brightness to user at max + * @test: The KUnit test context + */ +static void dm_test_brightness_to_user_at_max(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + + get_brightness_range(&caps, &min, &max); + + /* At max → should return max */ + KUNIT_EXPECT_EQ(test, convert_brightness_to_user(&caps, max), max); +} + +/** + * dm_test_brightness_to_user_at_min - Test Brightness to user at min + * @test: The KUnit test context + */ +static void dm_test_brightness_to_user_at_min(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + + get_brightness_range(&caps, &min, &max); + + /* At min → should return 0 */ + KUNIT_EXPECT_EQ(test, convert_brightness_to_user(&caps, min), 0U); +} + +/** + * dm_test_brightness_to_user_midpoint_pwm - Test Brightness to user midpoint pwm + * @test: The KUnit test context + */ +static void dm_test_brightness_to_user_midpoint_pwm(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max, mid_hw, result; + u64 expected; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + + get_brightness_range(&caps, &min, &max); + + /* midpoint of hw range */ + mid_hw = min + (max - min) / 2; + /* expected = DIV_ROUND_CLOSEST_ULL((u64)max * (mid_hw - min), max - min) */ + expected = DIV_ROUND_CLOSEST_ULL((u64)max * (mid_hw - min), max - min); + result = convert_brightness_to_user(&caps, mid_hw); + + KUNIT_EXPECT_EQ(test, result, (u32)expected); +} + +/* Tests for convert_brightness_from_user() — no custom curve */ + +/** + * dm_test_brightness_from_user_null_caps - Test Brightness from user null caps + * @test: The KUnit test context + */ +static void dm_test_brightness_from_user_null_caps(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, convert_brightness_from_user(NULL, 100), 100U); +} + +/** + * dm_test_brightness_from_user_zero - Test Brightness from user zero + * @test: The KUnit test context + */ +static void dm_test_brightness_from_user_zero(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + /* no custom curve */ + caps.data_points = 0; + + get_brightness_range(&caps, &min, &max); + + /* brightness=0 → min + 0 = min */ + KUNIT_EXPECT_EQ(test, convert_brightness_from_user(&caps, 0), (u32)min); +} + +/** + * dm_test_brightness_from_user_max - Test Brightness from user max + * @test: The KUnit test context + */ +static void dm_test_brightness_from_user_max(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 0; + + get_brightness_range(&caps, &min, &max); + + /* + * brightness=max → min + DIV_ROUND_CLOSEST((max-min)*max, max) + * = min + (max - min) = max + */ + KUNIT_EXPECT_EQ(test, convert_brightness_from_user(&caps, max), (u32)max); +} + +/** + * dm_test_brightness_from_user_aux - Test Brightness from user aux + * @test: The KUnit test context + */ +static void dm_test_brightness_from_user_aux(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.aux_support = true; + caps.aux_min_input_signal = 1; + caps.aux_max_input_signal = 512; + caps.data_points = 0; + + get_brightness_range(&caps, &min, &max); + + /* brightness=0 → min */ + KUNIT_EXPECT_EQ(test, convert_brightness_from_user(&caps, 0), (u32)min); + /* brightness=max → max */ + KUNIT_EXPECT_EQ(test, convert_brightness_from_user(&caps, max), (u32)max); +} + +/* Tests for convert_custom_brightness() */ + +/** + * dm_test_custom_brightness_no_data_points - Test Custom brightness no data points + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_no_data_points(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness = 128; + uint32_t saved = brightness; + + caps.data_points = 0; + + convert_custom_brightness(&caps, 3084, 65535, &brightness); + + /* No data points → no-op */ + KUNIT_EXPECT_EQ(test, brightness, saved); +} + +/** + * dm_test_custom_brightness_debug_mask_disables - Test Custom brightness debug mask disables + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_debug_mask_disables(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness = 128; + uint32_t saved = brightness; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + caps.data_points = 3; + caps.luminance_data[0].input_signal = 50; + caps.luminance_data[0].luminance = 10; + + /* Set the disable flag */ + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() | DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + convert_custom_brightness(&caps, 3084, 65535, &brightness); + + /* Should be no-op due to debug mask */ + KUNIT_EXPECT_EQ(test, brightness, saved); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_custom_brightness_exact_match - Test Custom brightness exact match + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_exact_match(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness; + unsigned int min, max; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() & ~DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 3; + caps.luminance_data[0].input_signal = 50; + caps.luminance_data[0].luminance = 20; + caps.luminance_data[1].input_signal = 128; + caps.luminance_data[1].luminance = 50; + caps.luminance_data[2].input_signal = 200; + caps.luminance_data[2].luminance = 90; + + get_brightness_range(&caps, &min, &max); + + /* + * Set brightness so that scale_input_to_fw yields exactly 128. + * scale_input_to_fw(min, max, x) = DIV_ROUND_CLOSEST(x * 255, max - min) + * With min=0, max=0x101*255=65535: + * We need x such that DIV_ROUND_CLOSEST(x * 255, 65535) = 128 + * → x = 128 * 65535 / 255 = 32896 + */ + brightness = 32896; + + convert_custom_brightness(&caps, min, max, &brightness); + + /* + * Exact match: lum=50, brightness_scaled=128 + * result = scale_fw_to_input(min, max, DIV_ROUND_CLOSEST(50*128, 101)) + * = scale_fw_to_input(0, 65535, DIV_ROUND_CLOSEST(6400, 101)) + * = scale_fw_to_input(0, 65535, 63) + * = 0 + DIV_ROUND_CLOSEST(63 * 65535, 255) = 16191 (approx) + */ + KUNIT_EXPECT_TRUE(test, brightness != 32896); + KUNIT_EXPECT_TRUE(test, brightness < 32896); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_custom_brightness_below_first - Test Custom brightness below first + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_below_first(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness; + unsigned int min, max; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() & ~DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 2; + caps.luminance_data[0].input_signal = 100; + caps.luminance_data[0].luminance = 40; + caps.luminance_data[1].input_signal = 200; + caps.luminance_data[1].luminance = 80; + + get_brightness_range(&caps, &min, &max); + + /* + * Set brightness low enough that scaled value < 100. + * scale_input_to_fw(0, 65535, x) = DIV_ROUND_CLOSEST(x*255, 65535) + * For result=50: x = 50*65535/255 = 12850 + */ + brightness = 12850; + + convert_custom_brightness(&caps, min, max, &brightness); + + /* + * Below first data point: lum = DIV_ROUND_CLOSEST(40 * 50, 100) = 20 + * Then: scale_fw_to_input(0, 65535, DIV_ROUND_CLOSEST(20 * 50, 101)) + * = scale_fw_to_input(0, 65535, DIV_ROUND_CLOSEST(1000, 101)) + * = scale_fw_to_input(0, 65535, 10) + * The output should be significantly less than input. + */ + KUNIT_EXPECT_TRUE(test, brightness < 12850); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_custom_brightness_interpolation - Test Custom brightness interpolation + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_interpolation(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness; + unsigned int min, max; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() & ~DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 2; + caps.luminance_data[0].input_signal = 50; + caps.luminance_data[0].luminance = 20; + caps.luminance_data[1].input_signal = 200; + caps.luminance_data[1].luminance = 80; + + get_brightness_range(&caps, &min, &max); + + /* + * Choose a value between data points 50 and 200. + * scale_input_to_fw(0, 65535, x) = 125 when x = 125*65535/255 = 32125 + */ + brightness = 32125; + + convert_custom_brightness(&caps, min, max, &brightness); + + /* + * The function should interpolate between data points and produce + * a remapped value different from the input. + */ + KUNIT_EXPECT_TRUE(test, brightness != 32125); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_custom_brightness_above_last - Test Custom brightness above last data point + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_above_last(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness; + unsigned int min, max; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() & ~DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 2; + caps.luminance_data[0].input_signal = 50; + caps.luminance_data[0].luminance = 20; + caps.luminance_data[1].input_signal = 150; + caps.luminance_data[1].luminance = 60; + + get_brightness_range(&caps, &min, &max); + + /* + * Choose brightness above the last data point (150). + * scale_input_to_fw(0, 65535, x) = 220 when x = 220*65535/255 = 56533 + * After binary search, left >= data_points, clamped → right==left, + * so lum = upper_lum = 60. + */ + brightness = 56533; + + convert_custom_brightness(&caps, min, max, &brightness); + + /* Output should differ from input (remapped via curve) */ + KUNIT_EXPECT_TRUE(test, brightness != 56533); + KUNIT_EXPECT_TRUE(test, brightness < 56533); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_custom_brightness_single_data_point - Test Custom brightness with single data point + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_single_data_point(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness; + unsigned int min, max; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() & ~DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 1; + caps.luminance_data[0].input_signal = 128; + caps.luminance_data[0].luminance = 50; + + get_brightness_range(&caps, &min, &max); + + /* + * Brightness below the single data point triggers the + * "below first" path: lum = DIV_ROUND_CLOSEST(50 * scaled, 128). + * scale_input_to_fw(0, 65535, x) = 64 when x = 64*65535/255 = 16448 + */ + brightness = 16448; + + convert_custom_brightness(&caps, min, max, &brightness); + + KUNIT_EXPECT_TRUE(test, brightness < 16448); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_custom_brightness_lower_lum_zero - Test Custom brightness with zero lower luminance + * @test: The KUnit test context + */ +static void dm_test_custom_brightness_lower_lum_zero(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + uint32_t brightness; + unsigned int min, max; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() & ~DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 2; + caps.luminance_data[0].input_signal = 50; + caps.luminance_data[0].luminance = 0; /* zero lower luminance */ + caps.luminance_data[1].input_signal = 200; + caps.luminance_data[1].luminance = 80; + + get_brightness_range(&caps, &min, &max); + + /* + * Choose brightness between data points to trigger interpolation. + * scale_input_to_fw(0, 65535, x) = 125 when x = 125*65535/255 = 32125 + * With lower_lum == 0, code takes shortcut: lum = upper_lum = 80. + */ + brightness = 32125; + + convert_custom_brightness(&caps, min, max, &brightness); + + /* Should remap; result should differ from input */ + KUNIT_EXPECT_TRUE(test, brightness != 32125); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_brightness_to_user_above_max - Test Brightness to user above max + * @test: The KUnit test context + */ +static void dm_test_brightness_to_user_above_max(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max, result; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + + get_brightness_range(&caps, &min, &max); + + /* brightness above max → result > max (linear extrapolation) */ + result = convert_brightness_to_user(&caps, max + 1000); + + KUNIT_EXPECT_GT(test, result, max); +} + +/** + * dm_test_brightness_from_user_midrange - Test Brightness from user mid-range value + * @test: The KUnit test context + */ +static void dm_test_brightness_from_user_midrange(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + u32 result; + + caps.aux_support = false; + caps.min_input_signal = AMDGPU_DM_DEFAULT_MIN_BACKLIGHT; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 0; + + get_brightness_range(&caps, &min, &max); + + /* Mid-range brightness should map to between min and max */ + result = convert_brightness_from_user(&caps, max / 2); + + KUNIT_EXPECT_GE(test, result, min); + KUNIT_EXPECT_LE(test, result, max); +} + +/** + * dm_test_brightness_from_user_with_curve - Test Brightness from user with custom curve active + * @test: The KUnit test context + */ +static void dm_test_brightness_from_user_with_curve(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + u32 with_curve, without_curve; + uint saved_mask = amdgpu_dm_get_dc_debug_mask(); + + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() & ~DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = AMDGPU_DM_DEFAULT_MAX_BACKLIGHT; + caps.data_points = 2; + caps.luminance_data[0].input_signal = 50; + caps.luminance_data[0].luminance = 20; + caps.luminance_data[1].input_signal = 200; + caps.luminance_data[1].luminance = 80; + + get_brightness_range(&caps, &min, &max); + + with_curve = convert_brightness_from_user(&caps, max / 2); + + /* Now disable the curve and compare */ + amdgpu_dm_set_dc_debug_mask(amdgpu_dm_get_dc_debug_mask() | DC_DISABLE_CUSTOM_BRIGHTNESS_CURVE); + without_curve = convert_brightness_from_user(&caps, max / 2); + + /* Custom curve should produce a different mapping */ + KUNIT_EXPECT_NE(test, with_curve, without_curve); + + amdgpu_dm_set_dc_debug_mask(saved_mask); +} + +/** + * dm_test_brightness_range_zero_signals - Test Brightness range with zero min and max signals + * @test: The KUnit test context + */ +static void dm_test_brightness_range_zero_signals(struct kunit *test) +{ + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min = 99, max = 99; + + caps.aux_support = false; + caps.min_input_signal = 0; + caps.max_input_signal = 0; + + /* Both signals zero → min=max=0 */ + KUNIT_EXPECT_EQ(test, get_brightness_range(&caps, &min, &max), 1); + KUNIT_EXPECT_EQ(test, min, 0U); + KUNIT_EXPECT_EQ(test, max, 0U); +} + +/* Tests for amdgpu_dm_backlight_fill_props() */ + +/** + * dm_test_backlight_fill_props_ac_linear - Test AC brightness and linear scale + * @test: The KUnit test context + */ +static void dm_test_backlight_fill_props_ac_linear(struct kunit *test) +{ + struct backlight_properties props = {}; + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.min_input_signal = 12; + caps.max_input_signal = 255; + caps.ac_level = 40; + caps.dc_level = 20; + + get_brightness_range(&caps, &min, &max); + amdgpu_dm_backlight_fill_props(&caps, true, false, &props); + + KUNIT_EXPECT_EQ(test, props.brightness, + DIV_ROUND_CLOSEST((max - min) * caps.ac_level, 100)); + KUNIT_EXPECT_EQ(test, props.max_brightness, max - min); + KUNIT_EXPECT_EQ(test, props.scale, BACKLIGHT_SCALE_LINEAR); + KUNIT_EXPECT_EQ(test, props.type, BACKLIGHT_RAW); +} + +/** + * dm_test_backlight_fill_props_dc_nonlinear - Test DC brightness and non-linear scale + * @test: The KUnit test context + */ +static void dm_test_backlight_fill_props_dc_nonlinear(struct kunit *test) +{ + struct backlight_properties props = {}; + struct amdgpu_dm_backlight_caps caps = {}; + unsigned int min, max; + + caps.min_input_signal = 12; + caps.max_input_signal = 255; + caps.ac_level = 40; + caps.dc_level = 20; + caps.data_points = 2; + + get_brightness_range(&caps, &min, &max); + amdgpu_dm_backlight_fill_props(&caps, false, true, &props); + + KUNIT_EXPECT_EQ(test, props.brightness, + DIV_ROUND_CLOSEST((max - min) * caps.dc_level, 100)); + KUNIT_EXPECT_EQ(test, props.max_brightness, max - min); + KUNIT_EXPECT_EQ(test, props.scale, BACKLIGHT_SCALE_NON_LINEAR); + KUNIT_EXPECT_EQ(test, props.type, BACKLIGHT_RAW); +} + +/** + * dm_test_backlight_fill_props_default_range - Test default properties without caps + * @test: The KUnit test context + */ +static void dm_test_backlight_fill_props_default_range(struct kunit *test) +{ + struct backlight_properties props = {}; + + amdgpu_dm_backlight_fill_props(NULL, false, true, &props); + + KUNIT_EXPECT_EQ(test, props.brightness, MAX_BACKLIGHT_LEVEL); + KUNIT_EXPECT_EQ(test, props.max_brightness, MAX_BACKLIGHT_LEVEL); + KUNIT_EXPECT_EQ(test, props.scale, BACKLIGHT_SCALE_LINEAR); + KUNIT_EXPECT_EQ(test, props.type, BACKLIGHT_RAW); +} + +/* Tests for amdgpu_dm_update_connector_ext_caps() */ + +/** + * dm_test_update_connector_ext_caps_negative_bl_idx - Test negative backlight index early return + * @test: The KUnit test context + */ +static void dm_test_update_connector_ext_caps_negative_bl_idx(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + + aconnector->bl_idx = -1; + + amdgpu_dm_update_connector_ext_caps(aconnector); + + KUNIT_SUCCEED(test); +} + +/** + * dm_test_update_connector_ext_caps_non_edp - Test non-eDP connector early return + * @test: The KUnit test context + */ +static void dm_test_update_connector_ext_caps_non_edp(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_HDMI_TYPE_A); + fixture.adev->dm.backlight_caps[0].aux_support = true; + + amdgpu_dm_update_connector_ext_caps(fixture.aconnector); + + KUNIT_EXPECT_TRUE(test, fixture.adev->dm.backlight_caps[0].aux_support); + KUNIT_EXPECT_PTR_EQ(test, fixture.adev->dm.backlight_caps[0].ext_caps, NULL); +} + +/** + * dm_test_update_connector_ext_caps_oled_defaults - Test OLED eDP defaults to AUX backlight + * @test: The KUnit test context + */ +static void dm_test_update_connector_ext_caps_oled_defaults(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_backlight = amdgpu_dm_get_backlight_param(); + + amdgpu_dm_set_backlight_param(-1); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_EDP); + fixture.link->dpcd_sink_ext_caps.bits.oled = 1; + + amdgpu_dm_update_connector_ext_caps(fixture.aconnector); + + KUNIT_EXPECT_PTR_EQ(test, fixture.adev->dm.backlight_caps[0].ext_caps, + &fixture.link->dpcd_sink_ext_caps); + KUNIT_EXPECT_TRUE(test, fixture.adev->dm.backlight_caps[0].aux_support); + KUNIT_EXPECT_EQ(test, fixture.link->backlight_control_type, + BACKLIGHT_CONTROL_AMD_AUX); + KUNIT_EXPECT_EQ(test, fixture.adev->dm.backlight_caps[0].aux_max_input_signal, 512); + KUNIT_EXPECT_EQ(test, fixture.adev->dm.backlight_caps[0].aux_min_input_signal, 1); + + amdgpu_dm_set_backlight_param(saved_backlight); +} + +/** + * dm_test_update_connector_ext_caps_luminance_values - Test luminance range copy + * @test: The KUnit test context + */ +static void dm_test_update_connector_ext_caps_luminance_values(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_backlight = amdgpu_dm_get_backlight_param(); + + amdgpu_dm_set_backlight_param(-1); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_EDP); + fixture.aconnector->base.display_info.luminance_range.min_luminance = 2; + fixture.aconnector->base.display_info.luminance_range.max_luminance = 400; + + amdgpu_dm_update_connector_ext_caps(fixture.aconnector); + + KUNIT_EXPECT_FALSE(test, fixture.adev->dm.backlight_caps[0].aux_support); + KUNIT_EXPECT_EQ(test, fixture.adev->dm.backlight_caps[0].aux_max_input_signal, 400); + KUNIT_EXPECT_EQ(test, fixture.adev->dm.backlight_caps[0].aux_min_input_signal, 2); + + amdgpu_dm_set_backlight_param(saved_backlight); +} + +/** + * dm_test_update_connector_ext_caps_force_aux - Test module parameter forces AUX backlight + * @test: The KUnit test context + */ +static void dm_test_update_connector_ext_caps_force_aux(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_backlight = amdgpu_dm_get_backlight_param(); + + amdgpu_dm_set_backlight_param(1); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_EDP); + + amdgpu_dm_update_connector_ext_caps(fixture.aconnector); + + KUNIT_EXPECT_TRUE(test, fixture.adev->dm.backlight_caps[0].aux_support); + KUNIT_EXPECT_EQ(test, fixture.link->backlight_control_type, + BACKLIGHT_CONTROL_AMD_AUX); + + amdgpu_dm_set_backlight_param(saved_backlight); +} + +/** + * dm_test_update_connector_ext_caps_force_pwm - Test module parameter forces PWM backlight + * @test: The KUnit test context + */ +static void dm_test_update_connector_ext_caps_force_pwm(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_backlight = amdgpu_dm_get_backlight_param(); + + amdgpu_dm_set_backlight_param(0); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_EDP); + fixture.link->dpcd_sink_ext_caps.bits.oled = 1; + + amdgpu_dm_update_connector_ext_caps(fixture.aconnector); + + KUNIT_EXPECT_FALSE(test, fixture.adev->dm.backlight_caps[0].aux_support); + KUNIT_EXPECT_NE(test, fixture.link->backlight_control_type, + BACKLIGHT_CONTROL_AMD_AUX); + + amdgpu_dm_set_backlight_param(saved_backlight); +} + +/* Tests for amdgpu_dm_should_create_sysfs() */ + +/** + * dm_test_should_create_sysfs_abm_forced - Test forced ABM disables sysfs + * @test: The KUnit test context + */ +static void dm_test_should_create_sysfs_abm_forced(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_abm_level = amdgpu_dm_get_abm_level_param(); + + amdgpu_dm_set_abm_level_param(1); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_EDP); + fixture.aconnector->base.connector_type = DRM_MODE_CONNECTOR_eDP; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_should_create_sysfs(fixture.aconnector)); + + amdgpu_dm_set_abm_level_param(saved_abm_level); +} + +/** + * dm_test_should_create_sysfs_non_edp - Test non-eDP connector disables sysfs + * @test: The KUnit test context + */ +static void dm_test_should_create_sysfs_non_edp(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_abm_level = amdgpu_dm_get_abm_level_param(); + + amdgpu_dm_set_abm_level_param(-1); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_HDMI_TYPE_A); + fixture.aconnector->base.connector_type = DRM_MODE_CONNECTOR_HDMIA; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_should_create_sysfs(fixture.aconnector)); + + amdgpu_dm_set_abm_level_param(saved_abm_level); +} + +/** + * dm_test_should_create_sysfs_no_backlight_index - Test eDP without backlight index enables sysfs + * @test: The KUnit test context + */ +static void dm_test_should_create_sysfs_no_backlight_index(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_abm_level = amdgpu_dm_get_abm_level_param(); + + amdgpu_dm_set_abm_level_param(-1); + setup_test_connector(test, &fixture, -1, SIGNAL_TYPE_EDP); + fixture.aconnector->base.connector_type = DRM_MODE_CONNECTOR_eDP; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_should_create_sysfs(fixture.aconnector)); + + amdgpu_dm_set_abm_level_param(saved_abm_level); +} + +/** + * dm_test_should_create_sysfs_aux_backlight - Test AUX backlight disables sysfs + * @test: The KUnit test context + */ +static void dm_test_should_create_sysfs_aux_backlight(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_abm_level = amdgpu_dm_get_abm_level_param(); + + amdgpu_dm_set_abm_level_param(-1); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_EDP); + fixture.aconnector->base.connector_type = DRM_MODE_CONNECTOR_eDP; + fixture.adev->dm.backlight_caps[0].aux_support = true; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_should_create_sysfs(fixture.aconnector)); + + amdgpu_dm_set_abm_level_param(saved_abm_level); +} + +/** + * dm_test_should_create_sysfs_pwm_backlight - Test PWM backlight enables sysfs + * @test: The KUnit test context + */ +static void dm_test_should_create_sysfs_pwm_backlight(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + int saved_abm_level = amdgpu_dm_get_abm_level_param(); + + amdgpu_dm_set_abm_level_param(-1); + setup_test_connector(test, &fixture, 0, SIGNAL_TYPE_EDP); + fixture.aconnector->base.connector_type = DRM_MODE_CONNECTOR_eDP; + fixture.adev->dm.backlight_caps[0].aux_support = false; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_should_create_sysfs(fixture.aconnector)); + + amdgpu_dm_set_abm_level_param(saved_abm_level); +} + +/* Tests for amdgpu_dm_setup_backlight_device() */ + +/** + * dm_test_setup_backlight_device_non_edp - Test non-eDP/LVDS link is skipped + * @test: The KUnit test context + */ +static void dm_test_setup_backlight_device_non_edp(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + struct amdgpu_display_manager *dm; + + setup_test_connector(test, &fixture, -1, SIGNAL_TYPE_HDMI_TYPE_A); + fixture.link->type = dc_connection_single; + dm = &fixture.adev->dm; + dm->adev = fixture.adev; + dm->num_of_edps = 0; + + amdgpu_dm_setup_backlight_device(dm, fixture.aconnector); + + /* Non-eDP/LVDS signal → no backlight setup */ + KUNIT_EXPECT_EQ(test, dm->num_of_edps, 0); + KUNIT_EXPECT_EQ(test, fixture.aconnector->bl_idx, -1); +} + +/** + * dm_test_setup_backlight_device_connection_none - Test disconnected link is skipped + * @test: The KUnit test context + */ +static void dm_test_setup_backlight_device_connection_none(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + struct amdgpu_display_manager *dm; + + setup_test_connector(test, &fixture, -1, SIGNAL_TYPE_EDP); + fixture.link->type = dc_connection_none; + dm = &fixture.adev->dm; + dm->adev = fixture.adev; + dm->num_of_edps = 0; + + amdgpu_dm_setup_backlight_device(dm, fixture.aconnector); + + /* Disconnected link → no backlight setup */ + KUNIT_EXPECT_EQ(test, dm->num_of_edps, 0); + KUNIT_EXPECT_EQ(test, fixture.aconnector->bl_idx, -1); +} + +/** + * dm_test_setup_backlight_device_max_edps - Test setup is skipped when at eDP limit + * @test: The KUnit test context + */ +static void dm_test_setup_backlight_device_max_edps(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + struct amdgpu_display_manager *dm; + + setup_test_connector(test, &fixture, -1, SIGNAL_TYPE_EDP); + fixture.link->type = dc_connection_single; + dm = &fixture.adev->dm; + dm->adev = fixture.adev; + dm->num_of_edps = AMDGPU_DM_MAX_NUM_EDP; + + amdgpu_dm_setup_backlight_device(dm, fixture.aconnector); + + /* Already at the eDP limit → no additional setup */ + KUNIT_EXPECT_EQ(test, dm->num_of_edps, AMDGPU_DM_MAX_NUM_EDP); + KUNIT_EXPECT_EQ(test, fixture.aconnector->bl_idx, -1); +} + +/** + * dm_test_setup_backlight_device_oled_success - Test successful eDP backlight setup + * @test: The KUnit test context + */ +static void dm_test_setup_backlight_device_oled_success(struct kunit *test) +{ + struct dm_backlight_connector_fixture fixture = {}; + struct amdgpu_display_manager *dm; + int saved_backlight = amdgpu_dm_get_backlight_param(); + + amdgpu_dm_set_backlight_param(-1); + setup_test_connector(test, &fixture, -1, SIGNAL_TYPE_EDP); + fixture.link->type = dc_connection_single; + /* OLED panel avoids the ABM property attach path */ + fixture.link->dpcd_sink_ext_caps.bits.oled = 1; + dm = &fixture.adev->dm; + dm->adev = fixture.adev; + dm->num_of_edps = 0; + + amdgpu_dm_setup_backlight_device(dm, fixture.aconnector); + + KUNIT_EXPECT_EQ(test, dm->num_of_edps, 1); + KUNIT_EXPECT_EQ(test, fixture.aconnector->bl_idx, 0); + KUNIT_EXPECT_PTR_EQ(test, (void *)dm->backlight_link[0], + (void *)fixture.link); + KUNIT_EXPECT_TRUE(test, dm->backlight_caps[0].aux_support); + + amdgpu_dm_set_backlight_param(saved_backlight); +} + +static struct kunit_case dm_backlight_test_cases[] = { + /* amdgpu_dm_backlight_get_device_index */ + KUNIT_CASE(dm_test_backlight_device_index_matches_second), + KUNIT_CASE(dm_test_backlight_device_index_missing_fallback), + KUNIT_CASE(dm_test_backlight_caps_valid_short_circuit), +#if !defined(CONFIG_ACPI) + KUNIT_CASE(dm_test_backlight_caps_aux_support_noop), + KUNIT_CASE(dm_test_backlight_caps_non_aux_sets_defaults), +#endif + /* get_brightness_range */ + KUNIT_CASE(dm_test_brightness_range_null_caps), + KUNIT_CASE(dm_test_brightness_range_pwm), + KUNIT_CASE(dm_test_brightness_range_aux), + /* convert_brightness_to_user */ + KUNIT_CASE(dm_test_brightness_to_user_null_caps), + KUNIT_CASE(dm_test_brightness_to_user_below_min), + KUNIT_CASE(dm_test_brightness_to_user_at_max), + KUNIT_CASE(dm_test_brightness_to_user_at_min), + KUNIT_CASE(dm_test_brightness_to_user_midpoint_pwm), + /* convert_brightness_from_user */ + KUNIT_CASE(dm_test_brightness_from_user_null_caps), + KUNIT_CASE(dm_test_brightness_from_user_zero), + KUNIT_CASE(dm_test_brightness_from_user_max), + KUNIT_CASE(dm_test_brightness_from_user_aux), + /* convert_custom_brightness */ + KUNIT_CASE(dm_test_custom_brightness_no_data_points), + KUNIT_CASE(dm_test_custom_brightness_debug_mask_disables), + KUNIT_CASE(dm_test_custom_brightness_exact_match), + KUNIT_CASE(dm_test_custom_brightness_below_first), + KUNIT_CASE(dm_test_custom_brightness_interpolation), + KUNIT_CASE(dm_test_custom_brightness_above_last), + KUNIT_CASE(dm_test_custom_brightness_single_data_point), + KUNIT_CASE(dm_test_custom_brightness_lower_lum_zero), + KUNIT_CASE(dm_test_brightness_to_user_above_max), + KUNIT_CASE(dm_test_brightness_from_user_midrange), + KUNIT_CASE(dm_test_brightness_from_user_with_curve), + KUNIT_CASE(dm_test_brightness_range_zero_signals), + /* amdgpu_dm_backlight_fill_props */ + KUNIT_CASE(dm_test_backlight_fill_props_ac_linear), + KUNIT_CASE(dm_test_backlight_fill_props_dc_nonlinear), + KUNIT_CASE(dm_test_backlight_fill_props_default_range), + /* amdgpu_dm_update_connector_ext_caps */ + KUNIT_CASE(dm_test_update_connector_ext_caps_negative_bl_idx), + KUNIT_CASE(dm_test_update_connector_ext_caps_non_edp), + KUNIT_CASE(dm_test_update_connector_ext_caps_oled_defaults), + KUNIT_CASE(dm_test_update_connector_ext_caps_luminance_values), + KUNIT_CASE(dm_test_update_connector_ext_caps_force_aux), + KUNIT_CASE(dm_test_update_connector_ext_caps_force_pwm), + /* amdgpu_dm_should_create_sysfs */ + KUNIT_CASE(dm_test_should_create_sysfs_abm_forced), + KUNIT_CASE(dm_test_should_create_sysfs_non_edp), + KUNIT_CASE(dm_test_should_create_sysfs_no_backlight_index), + KUNIT_CASE(dm_test_should_create_sysfs_aux_backlight), + KUNIT_CASE(dm_test_should_create_sysfs_pwm_backlight), + /* amdgpu_dm_setup_backlight_device */ + KUNIT_CASE(dm_test_setup_backlight_device_non_edp), + KUNIT_CASE(dm_test_setup_backlight_device_connection_none), + KUNIT_CASE(dm_test_setup_backlight_device_max_edps), + KUNIT_CASE(dm_test_setup_backlight_device_oled_success), + {} +}; + +static struct kunit_suite dm_backlight_test_suite = { + .name = "amdgpu_dm_backlight", + .test_cases = dm_backlight_test_cases, +}; + +kunit_test_suite(dm_backlight_test_suite); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_backlight"); +MODULE_AUTHOR("AMD"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c index f943361b70e8..d64c7da20f2c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_color_test.c @@ -1159,19 +1159,19 @@ static void dm_test_verify_lut_sizes_invalid_degamma_valid_gamma(struct kunit *t */ static void dm_test_atomic_lut3d_zero_size(struct kunit *test) { - struct dc_3dlut *lut; + struct dc_plane_cm *cm; u32 initialized; - lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, lut); + cm = kunit_kzalloc(test, sizeof(*cm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, cm); /* Pre-set initialized so we can confirm it is cleared */ - lut->state.bits.initialized = 1; + cm->lut3d_func.state.bits.initialized = 1; - amdgpu_dm_atomic_lut3d(NULL, 0, lut); + amdgpu_dm_atomic_lut3d(NULL, 0, cm); /* Copy bit-field: typeof cannot be applied to a bit-field */ - initialized = lut->state.bits.initialized; + initialized = cm->lut3d_func.state.bits.initialized; KUNIT_EXPECT_EQ(test, initialized, 0U); } @@ -1183,22 +1183,22 @@ static void dm_test_atomic_lut3d_nonzero_state_bits(struct kunit *test) { const uint32_t lut3d_size = 5; struct drm_color_lut *lut_data; - struct dc_3dlut *lut; + struct dc_plane_cm *cm; u32 initialized; lut_data = kunit_kcalloc(test, lut3d_size, sizeof(*lut_data), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, lut_data); - lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, lut); + cm = kunit_kzalloc(test, sizeof(*cm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, cm); - amdgpu_dm_atomic_lut3d(lut_data, lut3d_size, lut); + amdgpu_dm_atomic_lut3d(lut_data, lut3d_size, cm); /* Copy bit-field: typeof cannot be applied to a bit-field */ - initialized = lut->state.bits.initialized; + initialized = cm->lut3d_func.state.bits.initialized; KUNIT_EXPECT_EQ(test, initialized, 1U); - KUNIT_EXPECT_FALSE(test, lut->lut_3d.use_tetrahedral_9); - KUNIT_EXPECT_TRUE(test, lut->lut_3d.use_12bits); + KUNIT_EXPECT_FALSE(test, cm->lut3d_func.lut_3d.use_tetrahedral_9); + KUNIT_EXPECT_TRUE(test, cm->lut3d_func.lut_3d.use_12bits); } /** @@ -1209,29 +1209,29 @@ static void dm_test_atomic_lut3d_data_forwarded(struct kunit *test) { const uint32_t lut3d_size = 5; struct drm_color_lut *lut_data; - struct dc_3dlut *lut; + struct dc_plane_cm *cm; lut_data = kunit_kcalloc(test, lut3d_size, sizeof(*lut_data), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, lut_data); - lut = kunit_kzalloc(test, sizeof(*lut), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, lut); + cm = kunit_kzalloc(test, sizeof(*cm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, cm); lut_data[0].red = 0xFFFF; lut_data[0].green = 0x8000; lut_data[0].blue = 0x4000; - amdgpu_dm_atomic_lut3d(lut_data, lut3d_size, lut); + amdgpu_dm_atomic_lut3d(lut_data, lut3d_size, cm); /* * use_tetrahedral_9 == false → data goes into tetrahedral_17. * lut[0] maps to lut0[0] (first element of the first group). */ - KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].red, + KUNIT_EXPECT_EQ(test, cm->lut3d_func.lut_3d.tetrahedral_17.lut0[0].red, drm_color_lut_extract(0xFFFF, MAX_COLOR_3DLUT_BITDEPTH)); - KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].green, + KUNIT_EXPECT_EQ(test, cm->lut3d_func.lut_3d.tetrahedral_17.lut0[0].green, drm_color_lut_extract(0x8000, MAX_COLOR_3DLUT_BITDEPTH)); - KUNIT_EXPECT_EQ(test, lut->lut_3d.tetrahedral_17.lut0[0].blue, + KUNIT_EXPECT_EQ(test, cm->lut3d_func.lut_3d.tetrahedral_17.lut0[0].blue, drm_color_lut_extract(0x4000, MAX_COLOR_3DLUT_BITDEPTH)); } @@ -1398,19 +1398,19 @@ static void dm_test_set_atomic_regamma_bypass(struct kunit *test) */ static void dm_test_atomic_shaper_lut_bypass(struct kunit *test) { - struct dc_transfer_func *func_shaper; + struct dc_plane_cm *cm; - func_shaper = kunit_kzalloc(test, sizeof(*func_shaper), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, func_shaper); + cm = kunit_kzalloc(test, sizeof(*cm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, cm); /* size=0 and tf=LINEAR: must take the bypass branch */ KUNIT_EXPECT_EQ(test, amdgpu_dm_atomic_shaper_lut(NULL, false, TRANSFER_FUNCTION_LINEAR, - 0, func_shaper), + 0, cm), 0); - KUNIT_EXPECT_EQ(test, (int)func_shaper->type, (int)TF_TYPE_BYPASS); - KUNIT_EXPECT_EQ(test, (int)func_shaper->tf, (int)TRANSFER_FUNCTION_LINEAR); + KUNIT_EXPECT_EQ(test, (int)cm->shaper_func.type, (int)TF_TYPE_BYPASS); + KUNIT_EXPECT_EQ(test, (int)cm->shaper_func.tf, (int)TRANSFER_FUNCTION_LINEAR); } /** @@ -1419,19 +1419,19 @@ static void dm_test_atomic_shaper_lut_bypass(struct kunit *test) */ static void dm_test_atomic_blend_lut_bypass(struct kunit *test) { - struct dc_transfer_func *func_blend; + struct dc_plane_cm *cm; - func_blend = kunit_kzalloc(test, sizeof(*func_blend), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, func_blend); + cm = kunit_kzalloc(test, sizeof(*cm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, cm); /* size=0 and tf=LINEAR: must take the bypass branch */ KUNIT_EXPECT_EQ(test, amdgpu_dm_atomic_blend_lut(NULL, false, TRANSFER_FUNCTION_LINEAR, - 0, func_blend), + 0, cm), 0); - KUNIT_EXPECT_EQ(test, (int)func_blend->type, (int)TF_TYPE_BYPASS); - KUNIT_EXPECT_EQ(test, (int)func_blend->tf, (int)TRANSFER_FUNCTION_LINEAR); + KUNIT_EXPECT_EQ(test, (int)cm->blend_func.type, (int)TF_TYPE_BYPASS); + KUNIT_EXPECT_EQ(test, (int)cm->blend_func.tf, (int)TRANSFER_FUNCTION_LINEAR); } /* ---- Tests for __set_colorop_in_tf_1d_curve ---- */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c index fa270ff28c6a..2e557ff66818 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_colorop_test.c @@ -9,7 +9,10 @@ #include #include +#include "dc.h" +#include "amdgpu.h" #include "amdgpu_dm_colorop.h" +#include "amdgpu_dm_kunit_test_helpers.h" /* Tests for amdgpu_dm_supported_degam_tfs */ @@ -133,6 +136,30 @@ static void kunit_colorop_pipeline_destroy(void *drm) drm_colorop_pipeline_destroy((struct drm_device *)drm); } +static void dm_expect_colorop_pipeline(struct kunit *test, struct drm_device *drm, + const struct drm_prop_enum_list *list, + const enum drm_colorop_type *expected, + int expected_count) +{ + struct drm_colorop *op, *first = NULL; + int i = 0; + + drm_for_each_colorop(op, drm) { + if (op->base.id == (uint32_t)list->type) { + first = op; + break; + } + } + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, first); + + for (op = first; op; op = op->next, i++) { + KUNIT_ASSERT_LT(test, i, expected_count); + KUNIT_EXPECT_EQ(test, op->type, expected[i]); + KUNIT_EXPECT_NOT_NULL(test, op->bypass_property); + } + KUNIT_EXPECT_EQ(test, i, expected_count); +} + /** * dm_test_initialize_default_pipeline() - Verify amdgpu_dm_build_default_pipeline() * produces the expected colorop chain with all ops bypassable. @@ -154,8 +181,6 @@ static void dm_test_initialize_default_pipeline(struct kunit *test) struct drm_device *drm; struct drm_plane *plane; struct drm_prop_enum_list list = {}; - struct drm_colorop *op, *first = NULL; - int i = 0; int ret; dev = drm_kunit_helper_alloc_device(test); @@ -185,20 +210,102 @@ static void dm_test_initialize_default_pipeline(struct kunit *test) KUNIT_ASSERT_EQ(test, ret, 0); kfree(list.name); - drm_for_each_colorop(op, drm) { - if (op->base.id == (uint32_t)list.type) { - first = op; - break; - } - } - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, first); + dm_expect_colorop_pipeline(test, drm, &list, expected, ARRAY_SIZE(expected)); +} - for (op = first; op; op = op->next, i++) { - KUNIT_ASSERT_LT(test, i, (int)ARRAY_SIZE(expected)); - KUNIT_EXPECT_EQ(test, op->type, expected[i]); - KUNIT_EXPECT_NOT_NULL(test, op->bypass_property); - } - KUNIT_EXPECT_EQ(test, i, (int)ARRAY_SIZE(expected)); +static void dm_test_initialize_default_pipeline_caps(struct kunit *test, + bool dpp_hw_3d_lut, + bool mpc_preblend, + const enum drm_colorop_type *expected, + int expected_count) +{ + struct drm_prop_enum_list list = {}; + struct amdgpu_device *adev; + struct drm_device *drm; + struct drm_plane *plane; + struct dc *dc; + int ret; + + adev = dm_kunit_alloc_adev(test); + drm = &adev->ddev; + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + adev->dm.dc = dc; + adev->dm.dc->caps.color.dpp.hw_3d_lut = dpp_hw_3d_lut; + adev->dm.dc->caps.color.mpc.preblend = mpc_preblend; + + plane = drm_kunit_helper_create_primary_plane(test, drm, + NULL, NULL, NULL, 0, NULL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane); + + kunit_add_action(test, kunit_colorop_pipeline_destroy, drm); + + ret = amdgpu_dm_initialize_default_pipeline(plane, &list); + KUNIT_ASSERT_EQ(test, ret, 0); + kfree(list.name); + + dm_expect_colorop_pipeline(test, drm, &list, expected, expected_count); +} + +/** + * dm_test_initialize_default_pipeline_dpp_3d_lut() - Test DPP 3D LUT cap. + * @test: KUnit test context. + */ +static void dm_test_initialize_default_pipeline_dpp_3d_lut(struct kunit *test) +{ + static const enum drm_colorop_type expected[] = { + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_MULTIPLIER, + DRM_COLOROP_CTM_3X4, + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_1D_LUT, + DRM_COLOROP_3D_LUT, + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_1D_LUT, + }; + + dm_test_initialize_default_pipeline_caps(test, true, false, + expected, ARRAY_SIZE(expected)); +} + +/** + * dm_test_initialize_default_pipeline_mpc_preblend() - Test MPC preblend cap. + * @test: KUnit test context. + */ +static void dm_test_initialize_default_pipeline_mpc_preblend(struct kunit *test) +{ + static const enum drm_colorop_type expected[] = { + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_MULTIPLIER, + DRM_COLOROP_CTM_3X4, + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_1D_LUT, + DRM_COLOROP_3D_LUT, + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_1D_LUT, + }; + + dm_test_initialize_default_pipeline_caps(test, false, true, + expected, ARRAY_SIZE(expected)); +} + +/** + * dm_test_initialize_default_pipeline_no_3d_lut() - Test no 3D LUT caps. + * @test: KUnit test context. + */ +static void dm_test_initialize_default_pipeline_no_3d_lut(struct kunit *test) +{ + static const enum drm_colorop_type expected[] = { + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_MULTIPLIER, + DRM_COLOROP_CTM_3X4, + DRM_COLOROP_1D_CURVE, + DRM_COLOROP_1D_LUT, + }; + + dm_test_initialize_default_pipeline_caps(test, false, false, + expected, ARRAY_SIZE(expected)); } static struct kunit_case dm_colorop_test_cases[] = { @@ -224,6 +331,9 @@ static struct kunit_case dm_colorop_test_cases[] = { KUNIT_CASE(dm_test_degam_and_blnd_tfs_match), /* amdgpu_dm_initialize_default_pipeline */ KUNIT_CASE(dm_test_initialize_default_pipeline), + KUNIT_CASE(dm_test_initialize_default_pipeline_dpp_3d_lut), + KUNIT_CASE(dm_test_initialize_default_pipeline_mpc_preblend), + KUNIT_CASE(dm_test_initialize_default_pipeline_no_3d_lut), {} }; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c new file mode 100644 index 000000000000..aa451064b30c --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c @@ -0,0 +1,2158 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_connector.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_display.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_connector.h" +#include "amdgpu_dm_backlight.h" +#include "include/grph_object_id.h" + +/* Tests for get_subconnector_type() */ + +/** + * dm_test_subconnector_type_none - Test Subconnector type none + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_none(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Native); +} + +/** + * dm_test_subconnector_type_vga - Test Subconnector type vga + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_vga(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_VGA); +} + +/** + * dm_test_subconnector_type_dvi_converter - Test Subconnector type dvi converter + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_dvi_converter(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_DVID); +} + +/** + * dm_test_subconnector_type_dvi_dongle - Test Subconnector type dvi dongle + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_dvi_dongle(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_DONGLE; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_DVID); +} + +/** + * dm_test_subconnector_type_hdmi_converter - Test Subconnector type hdmi converter + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_hdmi_converter(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_HDMIA); +} + +/** + * dm_test_subconnector_type_hdmi_dongle - Test Subconnector type hdmi dongle + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_hdmi_dongle(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_DONGLE; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_HDMIA); +} + +/** + * dm_test_subconnector_type_mismatched - Test Subconnector type mismatched + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_mismatched(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Unknown); +} + +/** + * dm_test_subconnector_type_default_unknown - Test Subconnector type default unknown + * @test: The KUnit test context + */ +static void dm_test_subconnector_type_default_unknown(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.dongle_type = (typeof(link->dpcd_caps.dongle_type))0x7f; + KUNIT_EXPECT_EQ(test, (int)get_subconnector_type(link), (int)DRM_MODE_SUBCONNECTOR_Unknown); +} + +/* Tests for get_output_content_type() */ + +/** + * dm_test_content_type_no_data - Test Content type no data + * @test: The KUnit test context + */ +static void dm_test_content_type_no_data(struct kunit *test) +{ + struct drm_connector_state state = {}; + + state.content_type = DRM_MODE_CONTENT_TYPE_NO_DATA; + KUNIT_EXPECT_EQ(test, (int)get_output_content_type(&state), (int)DISPLAY_CONTENT_TYPE_NO_DATA); +} + +/** + * dm_test_content_type_graphics - Test Content type graphics + * @test: The KUnit test context + */ +static void dm_test_content_type_graphics(struct kunit *test) +{ + struct drm_connector_state state = {}; + + state.content_type = DRM_MODE_CONTENT_TYPE_GRAPHICS; + KUNIT_EXPECT_EQ(test, (int)get_output_content_type(&state), (int)DISPLAY_CONTENT_TYPE_GRAPHICS); +} + +/** + * dm_test_content_type_photo - Test Content type photo + * @test: The KUnit test context + */ +static void dm_test_content_type_photo(struct kunit *test) +{ + struct drm_connector_state state = {}; + + state.content_type = DRM_MODE_CONTENT_TYPE_PHOTO; + KUNIT_EXPECT_EQ(test, (int)get_output_content_type(&state), (int)DISPLAY_CONTENT_TYPE_PHOTO); +} + +/** + * dm_test_content_type_cinema - Test Content type cinema + * @test: The KUnit test context + */ +static void dm_test_content_type_cinema(struct kunit *test) +{ + struct drm_connector_state state = {}; + + state.content_type = DRM_MODE_CONTENT_TYPE_CINEMA; + KUNIT_EXPECT_EQ(test, (int)get_output_content_type(&state), (int)DISPLAY_CONTENT_TYPE_CINEMA); +} + +/** + * dm_test_content_type_game - Test Content type game + * @test: The KUnit test context + */ +static void dm_test_content_type_game(struct kunit *test) +{ + struct drm_connector_state state = {}; + + state.content_type = DRM_MODE_CONTENT_TYPE_GAME; + KUNIT_EXPECT_EQ(test, (int)get_output_content_type(&state), (int)DISPLAY_CONTENT_TYPE_GAME); +} + +/** + * dm_test_content_type_unknown_defaults_no_data - Test unknown content type defaults to no data + * @test: The KUnit test context + */ +static void dm_test_content_type_unknown_defaults_no_data(struct kunit *test) +{ + struct drm_connector_state state = {}; + + state.content_type = 0x7f; + KUNIT_EXPECT_EQ(test, (int)get_output_content_type(&state), + (int)DISPLAY_CONTENT_TYPE_NO_DATA); +} + +/* Tests for adjust_colour_depth_from_display_info() */ + +/** + * dm_test_adjust_colour_depth_fits_at_888 - Test Adjust colour depth fits at 888 + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_fits_at_888(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + /* 1080p @ 148500 KHz = 1485000 in 100Hz units */ + timing.pix_clk_100hz = 1485000; + timing.display_color_depth = COLOR_DEPTH_888; + timing.pixel_encoding = PIXEL_ENCODING_RGB; + info.max_tmds_clock = 150000; /* 150 MHz */ + + KUNIT_EXPECT_TRUE(test, adjust_colour_depth_from_display_info(&timing, &info)); + KUNIT_EXPECT_EQ(test, (int)timing.display_color_depth, (int)COLOR_DEPTH_888); +} + +/** + * dm_test_adjust_colour_depth_reduces_to_888 - Test Adjust colour depth reduces to 888 + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_reduces_to_888(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + /* Request 10bpc but TMDS limit only allows 8bpc */ + timing.pix_clk_100hz = 1485000; + timing.display_color_depth = COLOR_DEPTH_101010; + timing.pixel_encoding = PIXEL_ENCODING_RGB; + /* 10bpc would need 148500*30/24 = 185625 KHz, exceeds limit */ + info.max_tmds_clock = 160000; + + KUNIT_EXPECT_TRUE(test, adjust_colour_depth_from_display_info(&timing, &info)); + KUNIT_EXPECT_EQ(test, (int)timing.display_color_depth, (int)COLOR_DEPTH_888); +} + +/** + * dm_test_adjust_colour_depth_10bpc_passes - Test Adjust colour depth 10bpc passes + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_10bpc_passes(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + timing.pix_clk_100hz = 1485000; + timing.display_color_depth = COLOR_DEPTH_101010; + timing.pixel_encoding = PIXEL_ENCODING_RGB; + /* 10bpc needs 185625 KHz, allow it */ + info.max_tmds_clock = 200000; + + KUNIT_EXPECT_TRUE(test, adjust_colour_depth_from_display_info(&timing, &info)); + KUNIT_EXPECT_EQ(test, (int)timing.display_color_depth, (int)COLOR_DEPTH_101010); +} + +/** + * dm_test_adjust_colour_depth_420_halves_clk - Test Adjust colour depth 420 halves clk + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_420_halves_clk(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + /* 4K @ 594000 KHz = 5940000 in 100Hz units */ + timing.pix_clk_100hz = 5940000; + timing.display_color_depth = COLOR_DEPTH_101010; + timing.pixel_encoding = PIXEL_ENCODING_YCBCR420; + /* With 420: effective = 594000/2 = 297000, 10bpc = 297000*30/24 = 371250 */ + info.max_tmds_clock = 400000; + + KUNIT_EXPECT_TRUE(test, adjust_colour_depth_from_display_info(&timing, &info)); + KUNIT_EXPECT_EQ(test, (int)timing.display_color_depth, (int)COLOR_DEPTH_101010); +} + +/** + * dm_test_adjust_colour_depth_reduces_12bpc_to_10bpc - Test Adjust colour + * depth reduces 12bpc to 10bpc + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_reduces_12bpc_to_10bpc(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + timing.pix_clk_100hz = 1485000; + timing.display_color_depth = COLOR_DEPTH_121212; + timing.pixel_encoding = PIXEL_ENCODING_RGB; + info.max_tmds_clock = 190000; + + KUNIT_EXPECT_TRUE(test, adjust_colour_depth_from_display_info(&timing, &info)); + KUNIT_EXPECT_EQ(test, (int)timing.display_color_depth, (int)COLOR_DEPTH_101010); +} + +/** + * dm_test_adjust_colour_depth_16bpc_no_fallback - Test Adjust colour depth + * 16bpc cannot fall back + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_16bpc_no_fallback(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + /* 16bpc that exceeds limit cannot reduce because the next enum + * value (COLOR_DEPTH_141414) is not a valid HDMI depth. + */ + timing.pix_clk_100hz = 1485000; + timing.display_color_depth = COLOR_DEPTH_161616; + timing.pixel_encoding = PIXEL_ENCODING_RGB; + info.max_tmds_clock = 230000; + + KUNIT_EXPECT_FALSE(test, adjust_colour_depth_from_display_info(&timing, &info)); +} + +/** + * dm_test_adjust_colour_depth_none_fits - Test Adjust colour depth none fits + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_none_fits(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + /* Even 8bpc doesn't fit */ + timing.pix_clk_100hz = 1485000; + timing.display_color_depth = COLOR_DEPTH_888; + timing.pixel_encoding = PIXEL_ENCODING_RGB; + info.max_tmds_clock = 100000; /* Too low */ + + KUNIT_EXPECT_FALSE(test, adjust_colour_depth_from_display_info(&timing, &info)); +} + +/** + * dm_test_adjust_colour_depth_invalid_depth - Test Adjust colour depth invalid depth + * @test: The KUnit test context + */ +static void dm_test_adjust_colour_depth_invalid_depth(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_display_info info = {}; + + timing.pix_clk_100hz = 1485000; + timing.display_color_depth = COLOR_DEPTH_141414; + timing.pixel_encoding = PIXEL_ENCODING_RGB; + info.max_tmds_clock = 400000; + + KUNIT_EXPECT_FALSE(test, adjust_colour_depth_from_display_info(&timing, &info)); + KUNIT_EXPECT_EQ(test, (int)timing.display_color_depth, (int)COLOR_DEPTH_141414); +} + +/* Tests for amdgpu_dm_get_output_color_space() */ + +/** + * dm_test_output_color_space_default_rgb_full - Test Output color space default rgb full + * @test: The KUnit test context + */ +static void dm_test_output_color_space_default_rgb_full(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_RGB; + state.colorspace = DRM_MODE_COLORIMETRY_DEFAULT; + state.hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_SRGB); +} + +/** + * dm_test_output_color_space_default_rgb_limited - Test Output color space default rgb limited + * @test: The KUnit test context + */ +static void dm_test_output_color_space_default_rgb_limited(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_RGB; + state.colorspace = DRM_MODE_COLORIMETRY_DEFAULT; + state.hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_SRGB_LIMITED); +} + +/** + * dm_test_output_color_space_default_ycbcr709 - Test Output color space default ycbcr709 + * @test: The KUnit test context + */ +static void dm_test_output_color_space_default_ycbcr709(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_YCBCR444; + timing.pix_clk_100hz = 300000; + timing.flags.Y_ONLY = 0; + state.colorspace = DRM_MODE_COLORIMETRY_DEFAULT; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_YCBCR709); +} + +/** + * dm_test_output_color_space_default_ycbcr601_limited - Test Output color space + * default ycbcr601 limited + * @test: The KUnit test context + */ +static void dm_test_output_color_space_default_ycbcr601_limited(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_YCBCR444; + timing.pix_clk_100hz = 270300; + timing.flags.Y_ONLY = 1; + state.colorspace = DRM_MODE_COLORIMETRY_DEFAULT; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_YCBCR601_LIMITED); +} + +/** + * dm_test_output_color_space_bt601_y_only - Test Output color space bt601 y only + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt601_y_only(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.flags.Y_ONLY = 1; + state.colorspace = DRM_MODE_COLORIMETRY_BT601_YCC; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_YCBCR601_LIMITED); +} + +/** + * dm_test_output_color_space_bt601 - Test Output color space bt601 + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt601(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.flags.Y_ONLY = 0; + state.colorspace = DRM_MODE_COLORIMETRY_BT601_YCC; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_YCBCR601); +} + +/** + * dm_test_output_color_space_bt709 - Test Output color space bt709 + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt709(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.flags.Y_ONLY = 0; + state.colorspace = DRM_MODE_COLORIMETRY_BT709_YCC; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_YCBCR709); +} + +/** + * dm_test_output_color_space_bt709_y_only - Test Output color space bt709 y only + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt709_y_only(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.flags.Y_ONLY = 1; + state.colorspace = DRM_MODE_COLORIMETRY_BT709_YCC; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_YCBCR709_LIMITED); +} + +/** + * dm_test_output_color_space_oprgb - Test Output color space oprgb + * @test: The KUnit test context + */ +static void dm_test_output_color_space_oprgb(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + state.colorspace = DRM_MODE_COLORIMETRY_OPRGB; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_ADOBERGB); +} + +/** + * dm_test_output_color_space_bt2020_rgb - Test Output color space bt2020 rgb + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt2020_rgb(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_RGB; + state.colorspace = DRM_MODE_COLORIMETRY_BT2020_RGB; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_2020_RGB_FULLRANGE); +} + +/** + * dm_test_output_color_space_bt2020_ycc - Test Output color space bt2020 ycc + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt2020_ycc(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_YCBCR422; + state.colorspace = DRM_MODE_COLORIMETRY_BT2020_YCC; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_2020_YCBCR_LIMITED); +} + +/* Tests for amdgpu_dm_convert_dc_color_depth_into_bpc() */ + +/** + * dm_test_convert_color_depth_bpc_mappings - Test Convert color depth bpc mappings + * @test: The KUnit test context + */ +static void dm_test_convert_color_depth_bpc_mappings(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, amdgpu_dm_convert_dc_color_depth_into_bpc(COLOR_DEPTH_666), 6); + KUNIT_EXPECT_EQ(test, amdgpu_dm_convert_dc_color_depth_into_bpc(COLOR_DEPTH_888), 8); + KUNIT_EXPECT_EQ(test, amdgpu_dm_convert_dc_color_depth_into_bpc(COLOR_DEPTH_101010), 10); + KUNIT_EXPECT_EQ(test, amdgpu_dm_convert_dc_color_depth_into_bpc(COLOR_DEPTH_121212), 12); + KUNIT_EXPECT_EQ(test, amdgpu_dm_convert_dc_color_depth_into_bpc(COLOR_DEPTH_141414), 14); + KUNIT_EXPECT_EQ(test, amdgpu_dm_convert_dc_color_depth_into_bpc(COLOR_DEPTH_161616), 16); +} + +/** + * dm_test_convert_color_depth_bpc_unknown - Test Convert color depth bpc unknown + * @test: The KUnit test context + */ +static void dm_test_convert_color_depth_bpc_unknown(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, amdgpu_dm_convert_dc_color_depth_into_bpc(COLOR_DEPTH_UNDEFINED), 0); +} + +/* Tests for amdgpu_dm_convert_color_depth_from_display_info() */ + +/** + * dm_test_color_depth_from_info_bpc8 - Test Color depth from info bpc8 + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_bpc8(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.bpc = 8; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), + (int)COLOR_DEPTH_888); +} + +/** + * dm_test_color_depth_from_info_bpc10 - Test Color depth from info bpc10 + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_bpc10(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.bpc = 10; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), + (int)COLOR_DEPTH_101010); +} + +/** + * dm_test_color_depth_from_info_zero_bpc_defaults_888 - Test Color depth from + * info zero bpc defaults 888 + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_zero_bpc_defaults_888(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.bpc = 0; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), + (int)COLOR_DEPTH_888); +} + +/** + * dm_test_color_depth_from_info_requested_bpc_caps - Test Color depth from info requested bpc caps + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_requested_bpc_caps(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + /* Display supports 12bpc but user requests max 10 */ + connector->display_info.bpc = 12; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 10), + (int)COLOR_DEPTH_101010); +} + +/** + * dm_test_color_depth_from_info_y420_default - Test Color depth from info y420 default + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_y420_default(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + /* No Y420 DC modes set → 8bpc */ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), + (int)COLOR_DEPTH_888); +} + +/** + * dm_test_color_depth_from_info_y420_10bpc - Test Color depth from info y420 10bpc + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_y420_10bpc(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_30; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), + (int)COLOR_DEPTH_101010); +} + +/** + * dm_test_color_depth_from_info_y420_12bpc - Test Color depth from info y420 12bpc + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_y420_12bpc(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_36; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), + (int)COLOR_DEPTH_121212); +} + +/** + * dm_test_color_depth_from_info_y420_16bpc - Test Color depth from info y420 16bpc + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_y420_16bpc(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.hdmi.y420_dc_modes = DRM_EDID_YCBCR420_DC_48; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, true, 0), + (int)COLOR_DEPTH_161616); +} + +/** + * dm_test_color_depth_from_info_requested_odd_bpc - Test Color depth from info requested odd bpc + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_requested_odd_bpc(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.bpc = 12; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 11), + (int)COLOR_DEPTH_101010); +} + +/** + * dm_test_color_depth_from_info_unsupported_bpc - Test Color depth from info unsupported bpc + * @test: The KUnit test context + */ +static void dm_test_color_depth_from_info_unsupported_bpc(struct kunit *test) +{ + struct drm_connector *connector; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + + connector->display_info.bpc = 9; + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_convert_color_depth_from_display_info(connector, false, 0), + (int)COLOR_DEPTH_UNDEFINED); +} + +/* Tests for to_drm_connector_type() */ + +/** + * dm_test_to_connector_type_hdmi - Test To connector type hdmi + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_hdmi(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_HDMI_TYPE_A, 0), + DRM_MODE_CONNECTOR_HDMIA); +} + +/** + * dm_test_to_connector_type_edp - Test To connector type edp + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_edp(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_EDP, 0), + DRM_MODE_CONNECTOR_eDP); +} + +/** + * dm_test_to_connector_type_lvds - Test To connector type lvds + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_lvds(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_LVDS, 0), + DRM_MODE_CONNECTOR_LVDS); +} + +/** + * dm_test_to_connector_type_rgb - Test To connector type rgb + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_rgb(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_RGB, 0), + DRM_MODE_CONNECTOR_VGA); +} + +/** + * dm_test_to_connector_type_dp - Test To connector type dp + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_dp(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_DISPLAY_PORT, 0), + DRM_MODE_CONNECTOR_DisplayPort); +} + +/** + * dm_test_to_connector_type_dp_mst - Test To connector type dp mst + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_dp_mst(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_DISPLAY_PORT_MST, 0), + DRM_MODE_CONNECTOR_DisplayPort); +} + +/** + * dm_test_to_connector_type_dvi_dvii - Test To connector type dvi dvii + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_dvi_dvii(struct kunit *test) +{ + int type = to_drm_connector_type(SIGNAL_TYPE_DVI_SINGLE_LINK, CONNECTOR_ID_SINGLE_LINK_DVII); + + KUNIT_EXPECT_EQ(test, type, DRM_MODE_CONNECTOR_DVII); +} + +/** + * dm_test_to_connector_type_dual_link_dvii - Test To connector type dual link dvii + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_dual_link_dvii(struct kunit *test) +{ + int type = to_drm_connector_type(SIGNAL_TYPE_DVI_DUAL_LINK, CONNECTOR_ID_DUAL_LINK_DVII); + + KUNIT_EXPECT_EQ(test, type, DRM_MODE_CONNECTOR_DVII); +} + +/** + * dm_test_to_connector_type_dvi_dvid - Test To connector type dvi dvid + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_dvi_dvid(struct kunit *test) +{ + int type = to_drm_connector_type(SIGNAL_TYPE_DVI_SINGLE_LINK, CONNECTOR_ID_SINGLE_LINK_DVID); + + KUNIT_EXPECT_EQ(test, type, DRM_MODE_CONNECTOR_DVID); +} + +/** + * dm_test_to_connector_type_virtual - Test To connector type virtual + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_virtual(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_VIRTUAL, 0), + DRM_MODE_CONNECTOR_VIRTUAL); +} + +/** + * dm_test_to_connector_type_unknown - Test To connector type unknown + * @test: The KUnit test context + */ +static void dm_test_to_connector_type_unknown(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, to_drm_connector_type(SIGNAL_TYPE_NONE, 0), + DRM_MODE_CONNECTOR_Unknown); +} + +/* Tests for is_duplicate_mode() */ + +/** + * dm_test_is_duplicate_mode_empty_list - Test Is duplicate mode empty list + * @test: The KUnit test context + */ +static void dm_test_is_duplicate_mode_empty_list(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_display_mode mode = {}; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + + INIT_LIST_HEAD(&aconnector->base.probed_modes); + mode.hdisplay = 1920; + mode.vdisplay = 1080; + + KUNIT_EXPECT_FALSE(test, is_duplicate_mode(aconnector, &mode)); +} + +/** + * dm_test_is_duplicate_mode_match - Test Is duplicate mode match + * @test: The KUnit test context + */ +static void dm_test_is_duplicate_mode_match(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_display_mode existing = {}; + struct drm_display_mode candidate = {}; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + + INIT_LIST_HEAD(&aconnector->base.probed_modes); + existing.hdisplay = 1920; + existing.vdisplay = 1080; + existing.clock = 148500; + list_add_tail(&existing.head, &aconnector->base.probed_modes); + + candidate.hdisplay = 1920; + candidate.vdisplay = 1080; + candidate.clock = 148500; + + KUNIT_EXPECT_TRUE(test, is_duplicate_mode(aconnector, &candidate)); +} + +/** + * dm_test_is_duplicate_mode_no_match - Test Is duplicate mode no match + * @test: The KUnit test context + */ +static void dm_test_is_duplicate_mode_no_match(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_display_mode existing = {}; + struct drm_display_mode candidate = {}; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + + INIT_LIST_HEAD(&aconnector->base.probed_modes); + existing.hdisplay = 1920; + existing.vdisplay = 1080; + existing.clock = 148500; + list_add_tail(&existing.head, &aconnector->base.probed_modes); + + candidate.hdisplay = 2560; + candidate.vdisplay = 1440; + candidate.clock = 241500; + + KUNIT_EXPECT_FALSE(test, is_duplicate_mode(aconnector, &candidate)); +} + +/** + * dm_test_is_duplicate_mode_same_size_different_clock - Test Is duplicate mode + * same size different clock + * @test: The KUnit test context + */ +static void dm_test_is_duplicate_mode_same_size_different_clock(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_display_mode existing = {}; + struct drm_display_mode candidate = {}; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, aconnector); + + INIT_LIST_HEAD(&aconnector->base.probed_modes); + existing.hdisplay = 1920; + existing.vdisplay = 1080; + existing.clock = 148500; + list_add_tail(&existing.head, &aconnector->base.probed_modes); + + candidate.hdisplay = 1920; + candidate.vdisplay = 1080; + candidate.clock = 74250; + + KUNIT_EXPECT_FALSE(test, is_duplicate_mode(aconnector, &candidate)); +} + +/* Tests for amdgpu_dm_get_encoder_crtc_mask() */ + +/** + * dm_test_encoder_crtc_mask_1 - Test Encoder crtc mask 1 + * @test: The KUnit test context + */ +static void dm_test_encoder_crtc_mask_1(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->mode_info.num_crtc = 1; + KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x1); +} + +/** + * dm_test_encoder_crtc_mask_2 - Test Encoder crtc mask 2 + * @test: The KUnit test context + */ +static void dm_test_encoder_crtc_mask_2(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->mode_info.num_crtc = 2; + KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x3); +} + +/** + * dm_test_encoder_crtc_mask_3 - Test Encoder crtc mask 3 + * @test: The KUnit test context + */ +static void dm_test_encoder_crtc_mask_3(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->mode_info.num_crtc = 3; + KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x7); +} + +/** + * dm_test_encoder_crtc_mask_4 - Test Encoder crtc mask 4 + * @test: The KUnit test context + */ +static void dm_test_encoder_crtc_mask_4(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->mode_info.num_crtc = 4; + KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0xf); +} + +/** + * dm_test_encoder_crtc_mask_5 - Test Encoder crtc mask 5 + * @test: The KUnit test context + */ +static void dm_test_encoder_crtc_mask_5(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->mode_info.num_crtc = 5; + KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x1f); +} + +/** + * dm_test_encoder_crtc_mask_6 - Test Encoder crtc mask 6 + * @test: The KUnit test context + */ +static void dm_test_encoder_crtc_mask_6(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->mode_info.num_crtc = 6; + KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x3f); +} + +/** + * dm_test_encoder_crtc_mask_default - Test Encoder crtc mask default + * @test: The KUnit test context + */ +static void dm_test_encoder_crtc_mask_default(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + /* Values > 6 use the default case */ + adev->mode_info.num_crtc = 8; + KUNIT_EXPECT_EQ(test, amdgpu_dm_get_encoder_crtc_mask(adev), 0x3f); +} + +/* Tests for get_aspect_ratio() */ + +/** + * dm_test_aspect_ratio_no_data - Test Aspect ratio no data + * @test: The KUnit test context + */ +static void dm_test_aspect_ratio_no_data(struct kunit *test) +{ + struct drm_display_mode mode = {}; + + mode.picture_aspect_ratio = HDMI_PICTURE_ASPECT_NONE; + KUNIT_EXPECT_EQ(test, (int)get_aspect_ratio(&mode), (int)ASPECT_RATIO_NO_DATA); +} + +/** + * dm_test_aspect_ratio_4_3 - Test Aspect ratio 4 3 + * @test: The KUnit test context + */ +static void dm_test_aspect_ratio_4_3(struct kunit *test) +{ + struct drm_display_mode mode = {}; + + mode.picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3; + KUNIT_EXPECT_EQ(test, (int)get_aspect_ratio(&mode), (int)ASPECT_RATIO_4_3); +} + +/** + * dm_test_aspect_ratio_16_9 - Test Aspect ratio 16 9 + * @test: The KUnit test context + */ +static void dm_test_aspect_ratio_16_9(struct kunit *test) +{ + struct drm_display_mode mode = {}; + + mode.picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9; + KUNIT_EXPECT_EQ(test, (int)get_aspect_ratio(&mode), (int)ASPECT_RATIO_16_9); +} + +/** + * dm_test_aspect_ratio_64_27 - Test Aspect ratio 64 27 + * @test: The KUnit test context + */ +static void dm_test_aspect_ratio_64_27(struct kunit *test) +{ + struct drm_display_mode mode = {}; + + mode.picture_aspect_ratio = HDMI_PICTURE_ASPECT_64_27; + KUNIT_EXPECT_EQ(test, (int)get_aspect_ratio(&mode), (int)ASPECT_RATIO_64_27); +} + +/** + * dm_test_aspect_ratio_256_135 - Test Aspect ratio 256 135 + * @test: The KUnit test context + */ +static void dm_test_aspect_ratio_256_135(struct kunit *test) +{ + struct drm_display_mode mode = {}; + + mode.picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135; + KUNIT_EXPECT_EQ(test, (int)get_aspect_ratio(&mode), (int)ASPECT_RATIO_256_135); +} + +/* Tests for decide_crtc_timing_for_drm_display_mode() */ + +/** + * dm_test_decide_crtc_timing_scale_enabled - Test Decide crtc timing scale enabled + * @test: The KUnit test context + */ +static void dm_test_decide_crtc_timing_scale_enabled(struct kunit *test) +{ + struct drm_display_mode drm_mode = {}; + struct drm_display_mode native_mode = {}; + + native_mode.crtc_clock = 148500; + native_mode.crtc_hdisplay = 1920; + native_mode.crtc_vdisplay = 1080; + native_mode.crtc_htotal = 2200; + native_mode.crtc_vtotal = 1125; + native_mode.crtc_hsync_start = 2008; + native_mode.crtc_hsync_end = 2052; + native_mode.crtc_vsync_start = 1084; + native_mode.crtc_vsync_end = 1089; + + /* Different clock/htotal/vtotal, but scale_enabled forces copy */ + drm_mode.clock = 74250; + drm_mode.htotal = 1650; + drm_mode.vtotal = 750; + + decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, true); + + KUNIT_EXPECT_EQ(test, drm_mode.crtc_clock, 148500); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 1920); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_vdisplay, 1080); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_htotal, 2200); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_vtotal, 1125); +} + +/** + * dm_test_decide_crtc_timing_matching_mode - Test Decide crtc timing matching mode + * @test: The KUnit test context + */ +static void dm_test_decide_crtc_timing_matching_mode(struct kunit *test) +{ + struct drm_display_mode drm_mode = {}; + struct drm_display_mode native_mode = {}; + + native_mode.clock = 148500; + native_mode.htotal = 2200; + native_mode.vtotal = 1125; + native_mode.crtc_clock = 148500; + native_mode.crtc_hdisplay = 1920; + native_mode.crtc_vdisplay = 1080; + native_mode.crtc_htotal = 2200; + native_mode.crtc_vtotal = 1125; + + /* Matching clock/htotal/vtotal triggers copy */ + drm_mode.clock = 148500; + drm_mode.htotal = 2200; + drm_mode.vtotal = 1125; + + decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false); + + KUNIT_EXPECT_EQ(test, drm_mode.crtc_clock, 148500); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 1920); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_vtotal, 1125); +} + +/** + * dm_test_decide_crtc_timing_no_copy - Test Decide crtc timing no copy + * @test: The KUnit test context + */ +static void dm_test_decide_crtc_timing_no_copy(struct kunit *test) +{ + struct drm_display_mode drm_mode = {}; + struct drm_display_mode native_mode = {}; + + native_mode.clock = 148500; + native_mode.htotal = 2200; + native_mode.vtotal = 1125; + native_mode.crtc_clock = 148500; + native_mode.crtc_hdisplay = 1920; + + /* Different timings, no scaling → no copy */ + drm_mode.clock = 74250; + drm_mode.htotal = 1650; + drm_mode.vtotal = 750; + + decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false); + + KUNIT_EXPECT_EQ(test, drm_mode.crtc_clock, 0); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 0); +} + +/** + * dm_test_decide_crtc_timing_no_crtc_clock - Test Decide crtc timing no crtc clock + * @test: The KUnit test context + */ +static void dm_test_decide_crtc_timing_no_crtc_clock(struct kunit *test) +{ + struct drm_display_mode drm_mode = {}; + struct drm_display_mode native_mode = {}; + + /* Matching timings but native crtc_clock is 0 → no copy */ + native_mode.clock = 148500; + native_mode.htotal = 2200; + native_mode.vtotal = 1125; + native_mode.crtc_clock = 0; + native_mode.crtc_hdisplay = 1920; + + drm_mode.clock = 148500; + drm_mode.htotal = 2200; + drm_mode.vtotal = 1125; + + decide_crtc_timing_for_drm_display_mode(&drm_mode, &native_mode, false); + + KUNIT_EXPECT_EQ(test, drm_mode.crtc_clock, 0); + KUNIT_EXPECT_EQ(test, drm_mode.crtc_hdisplay, 0); +} + +/* Tests for amdgpu_dm_connector_funcs_reset() */ + +static const struct drm_connector_funcs dm_test_connector_funcs = { + .reset = amdgpu_dm_connector_funcs_reset, + .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, +}; + +/** + * dm_test_funcs_reset_sets_defaults - Test funcs_reset sets defaults + * @test: The KUnit test context + */ +static void dm_test_funcs_reset_sets_defaults(struct kunit *test) +{ + struct device *dev; + struct drm_device *drm; + struct drm_connector *connector; + struct dm_connector_state *dm_state; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(*drm), 0, + DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, connector); + + drmm_connector_init(drm, connector, &dm_test_connector_funcs, + DRM_MODE_CONNECTOR_DisplayPort, NULL); + + amdgpu_dm_connector_funcs_reset(connector); + + KUNIT_ASSERT_NOT_NULL(test, connector->state); + dm_state = to_dm_connector_state(connector->state); + KUNIT_EXPECT_EQ(test, (int)dm_state->scaling, (int)RMX_OFF); + KUNIT_EXPECT_FALSE(test, dm_state->underscan_enable); + KUNIT_EXPECT_EQ(test, (int)dm_state->underscan_hborder, 0); + KUNIT_EXPECT_EQ(test, (int)dm_state->underscan_vborder, 0); + KUNIT_EXPECT_EQ(test, (int)dm_state->base.max_requested_bpc, 8); + KUNIT_EXPECT_EQ(test, dm_state->vcpi_slots, 0); + KUNIT_EXPECT_EQ(test, (int)dm_state->pbn, 0); +} + +/** + * dm_test_funcs_reset_edp_abm_level - Test funcs_reset eDP sets ABM + * @test: The KUnit test context + */ +static void dm_test_funcs_reset_edp_abm_level(struct kunit *test) +{ + struct device *dev; + struct drm_device *drm; + struct drm_connector *connector; + struct dm_connector_state *dm_state; + int saved_abm_level = amdgpu_dm_get_abm_level_param(); + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(*drm), 0, + DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, connector); + + drmm_connector_init(drm, connector, &dm_test_connector_funcs, + DRM_MODE_CONNECTOR_eDP, NULL); + + /* Test with abm_level > 0 */ + amdgpu_dm_set_abm_level_param(3); + amdgpu_dm_connector_funcs_reset(connector); + + KUNIT_ASSERT_NOT_NULL(test, connector->state); + dm_state = to_dm_connector_state(connector->state); + KUNIT_EXPECT_EQ(test, (int)dm_state->abm_level, 3); + + amdgpu_dm_set_abm_level_param(saved_abm_level); +} + +/** + * dm_test_funcs_reset_edp_abm_disabled - Test funcs_reset eDP ABM + * disabled + * @test: The KUnit test context + */ +static void dm_test_funcs_reset_edp_abm_disabled(struct kunit *test) +{ + struct device *dev; + struct drm_device *drm; + struct drm_connector *connector; + struct dm_connector_state *dm_state; + int saved_abm_level = amdgpu_dm_get_abm_level_param(); + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(*drm), 0, + DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, connector); + + drmm_connector_init(drm, connector, &dm_test_connector_funcs, + DRM_MODE_CONNECTOR_eDP, NULL); + + /* Test with abm_level <= 0 → immediate disable */ + amdgpu_dm_set_abm_level_param(-1); + amdgpu_dm_connector_funcs_reset(connector); + + KUNIT_ASSERT_NOT_NULL(test, connector->state); + dm_state = to_dm_connector_state(connector->state); + KUNIT_EXPECT_EQ(test, (int)dm_state->abm_level, + (int)ABM_LEVEL_IMMEDIATE_DISABLE); + + amdgpu_dm_set_abm_level_param(saved_abm_level); +} + +/* Tests for amdgpu_dm_connector_atomic_duplicate_state() */ + +/** + * dm_test_atomic_dup_state_copies_fields - Test atomic_duplicate copies + * fields + * @test: The KUnit test context + */ +static void dm_test_atomic_dup_state_copies_fields(struct kunit *test) +{ + struct device *dev; + struct drm_device *drm; + struct drm_connector *connector; + struct dm_connector_state *dm_state; + struct dm_connector_state *new_dm_state; + struct drm_connector_state *new_state; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(*drm), 0, + DRIVER_MODESET); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, connector); + + drmm_connector_init(drm, connector, &dm_test_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA, NULL); + + amdgpu_dm_connector_funcs_reset(connector); + KUNIT_ASSERT_NOT_NULL(test, connector->state); + + /* Modify original state fields */ + dm_state = to_dm_connector_state(connector->state); + dm_state->scaling = RMX_CENTER; + dm_state->underscan_enable = true; + dm_state->underscan_hborder = 10; + dm_state->underscan_vborder = 20; + dm_state->freesync_capable = true; + dm_state->abm_level = 2; + dm_state->vcpi_slots = 4; + dm_state->pbn = 1234; + + /* Duplicate */ + new_state = amdgpu_dm_connector_atomic_duplicate_state(connector); + KUNIT_ASSERT_NOT_NULL(test, new_state); + new_dm_state = to_dm_connector_state(new_state); + + /* Verify all fields copied */ + KUNIT_EXPECT_EQ(test, (int)new_dm_state->scaling, (int)RMX_CENTER); + KUNIT_EXPECT_TRUE(test, new_dm_state->underscan_enable); + KUNIT_EXPECT_EQ(test, (int)new_dm_state->underscan_hborder, 10); + KUNIT_EXPECT_EQ(test, (int)new_dm_state->underscan_vborder, 20); + KUNIT_EXPECT_TRUE(test, new_dm_state->freesync_capable); + KUNIT_EXPECT_EQ(test, (int)new_dm_state->abm_level, 2); + KUNIT_EXPECT_EQ(test, new_dm_state->vcpi_slots, 4); + KUNIT_EXPECT_EQ(test, (int)new_dm_state->pbn, 1234); + + kfree(new_dm_state); +} + +/* Tests for amdgpu_dm_fill_hdr_info_packet() */ + +/** + * dm_test_fill_hdr_null_metadata - Test fill_hdr returns 0 with no + * metadata + * @test: The KUnit test context + */ +static void dm_test_fill_hdr_null_metadata(struct kunit *test) +{ + struct drm_connector_state state = {}; + struct dc_info_packet out = {}; + + /* No hdr_output_metadata → early return 0, out stays zeroed */ + state.hdr_output_metadata = NULL; + KUNIT_EXPECT_EQ(test, amdgpu_dm_fill_hdr_info_packet(&state, &out), 0); + KUNIT_EXPECT_FALSE(test, out.valid); +} + +/** + * dm_test_fill_hdr_zeroes_output - Test fill_hdr zeroes output with no + * metadata + * @test: The KUnit test context + */ +static void dm_test_fill_hdr_zeroes_output(struct kunit *test) +{ + struct drm_connector_state state = {}; + struct dc_info_packet out; + + /* Pre-fill out with nonzero to verify memset(0) */ + memset(&out, 0xAA, sizeof(out)); + + state.hdr_output_metadata = NULL; + KUNIT_EXPECT_EQ(test, amdgpu_dm_fill_hdr_info_packet(&state, &out), 0); + KUNIT_EXPECT_FALSE(test, out.valid); + KUNIT_EXPECT_EQ(test, (int)out.hb0, 0); + KUNIT_EXPECT_EQ(test, (int)out.hb1, 0); + KUNIT_EXPECT_EQ(test, (int)out.hb2, 0); + KUNIT_EXPECT_EQ(test, (int)out.hb3, 0); +} + +/* Tests for amdgpu_dm_connector_atomic_set_property() */ + +/* + * Build a connector wired to a kunit-allocated amdgpu_device so that + * drm_to_adev() resolves correctly, together with old/new dm states and + * the set of properties used by the get/set property handlers. + */ +struct dm_test_prop_ctx { + struct amdgpu_device *adev; + struct drm_connector *connector; + struct dm_connector_state *old_state; + struct dm_connector_state *new_state; + struct drm_property *scaling_prop; + struct drm_property *hborder_prop; + struct drm_property *vborder_prop; + struct drm_property *underscan_prop; + struct drm_property *abm_prop; +}; + +static struct dm_test_prop_ctx *dm_test_prop_ctx_alloc(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + ctx->adev = kunit_kzalloc(test, sizeof(*ctx->adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->adev); + ctx->connector = kunit_kzalloc(test, sizeof(*ctx->connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->connector); + ctx->old_state = kunit_kzalloc(test, sizeof(*ctx->old_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->old_state); + ctx->new_state = kunit_kzalloc(test, sizeof(*ctx->new_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->new_state); + ctx->scaling_prop = kunit_kzalloc(test, sizeof(*ctx->scaling_prop), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->scaling_prop); + ctx->hborder_prop = kunit_kzalloc(test, sizeof(*ctx->hborder_prop), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->hborder_prop); + ctx->vborder_prop = kunit_kzalloc(test, sizeof(*ctx->vborder_prop), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->vborder_prop); + ctx->underscan_prop = kunit_kzalloc(test, sizeof(*ctx->underscan_prop), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->underscan_prop); + ctx->abm_prop = kunit_kzalloc(test, sizeof(*ctx->abm_prop), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->abm_prop); + + ctx->connector->dev = &ctx->adev->ddev; + ctx->connector->state = &ctx->old_state->base; + + ctx->adev->ddev.mode_config.scaling_mode_property = ctx->scaling_prop; + ctx->adev->mode_info.underscan_hborder_property = ctx->hborder_prop; + ctx->adev->mode_info.underscan_vborder_property = ctx->vborder_prop; + ctx->adev->mode_info.underscan_property = ctx->underscan_prop; + ctx->adev->mode_info.abm_level_property = ctx->abm_prop; + + return ctx; +} + +/** + * dm_test_set_property_scaling_center - Test set scaling property to center + * @test: The KUnit test context + */ +static void dm_test_set_property_scaling_center(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, DRM_MODE_SCALE_CENTER), 0); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->scaling, (int)RMX_CENTER); +} + +/** + * dm_test_set_property_scaling_aspect - Test set scaling property to aspect + * @test: The KUnit test context + */ +static void dm_test_set_property_scaling_aspect(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, DRM_MODE_SCALE_ASPECT), 0); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->scaling, (int)RMX_ASPECT); +} + +/** + * dm_test_set_property_scaling_fullscreen - Test set scaling property to full + * @test: The KUnit test context + */ +static void dm_test_set_property_scaling_fullscreen(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, DRM_MODE_SCALE_FULLSCREEN), 0); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->scaling, (int)RMX_FULL); +} + +/** + * dm_test_set_property_scaling_none - Test set scaling property to none + * @test: The KUnit test context + */ +static void dm_test_set_property_scaling_none(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + /* old scaling is RMX_CENTER so RMX_OFF is a real change */ + ctx->old_state->scaling = RMX_CENTER; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, DRM_MODE_SCALE_NONE), 0); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->scaling, (int)RMX_OFF); +} + +/** + * dm_test_set_property_scaling_unchanged - Test set scaling property unchanged + * @test: The KUnit test context + */ +static void dm_test_set_property_scaling_unchanged(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + /* old already RMX_OFF, requesting NONE/OFF returns 0 without write */ + ctx->old_state->scaling = RMX_OFF; + ctx->new_state->scaling = RMX_CENTER; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, DRM_MODE_SCALE_NONE), 0); + /* new_state untouched because of early return */ + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->scaling, (int)RMX_CENTER); +} + +/** + * dm_test_set_property_underscan_hborder - Test set underscan hborder + * @test: The KUnit test context + */ +static void dm_test_set_property_underscan_hborder(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->hborder_prop, 42), 0); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->underscan_hborder, 42); +} + +/** + * dm_test_set_property_underscan_vborder - Test set underscan vborder + * @test: The KUnit test context + */ +static void dm_test_set_property_underscan_vborder(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->vborder_prop, 24), 0); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->underscan_vborder, 24); +} + +/** + * dm_test_set_property_underscan_enable - Test set underscan enable + * @test: The KUnit test context + */ +static void dm_test_set_property_underscan_enable(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->underscan_prop, 1), 0); + KUNIT_EXPECT_TRUE(test, ctx->new_state->underscan_enable); +} + +/** + * dm_test_set_property_abm_sysfs_control - Test set abm sysfs control + * @test: The KUnit test context + */ +static void dm_test_set_property_abm_sysfs_control(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + ctx->new_state->abm_sysfs_forbidden = true; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->abm_prop, ABM_SYSFS_CONTROL), 0); + KUNIT_EXPECT_FALSE(test, ctx->new_state->abm_sysfs_forbidden); +} + +/** + * dm_test_set_property_abm_level_off - Test set abm level off + * @test: The KUnit test context + */ +static void dm_test_set_property_abm_level_off(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->abm_prop, ABM_LEVEL_OFF), 0); + KUNIT_EXPECT_TRUE(test, ctx->new_state->abm_sysfs_forbidden); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->abm_level, + (int)ABM_LEVEL_IMMEDIATE_DISABLE); +} + +/** + * dm_test_set_property_abm_level_value - Test set abm level to a value + * @test: The KUnit test context + */ +static void dm_test_set_property_abm_level_value(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + ctx->abm_prop, 3), 0); + KUNIT_EXPECT_TRUE(test, ctx->new_state->abm_sysfs_forbidden); + KUNIT_EXPECT_EQ(test, (int)ctx->new_state->abm_level, 3); +} + +/** + * dm_test_set_property_unknown - Test set unknown property returns -EINVAL + * @test: The KUnit test context + */ +static void dm_test_set_property_unknown(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + struct drm_property *other; + + other = kunit_kzalloc(test, sizeof(*other), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, other); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_set_property( + ctx->connector, &ctx->new_state->base, + other, 0), -EINVAL); +} + +/* Tests for amdgpu_dm_connector_atomic_get_property() */ + +/** + * dm_test_get_property_scaling_center - Test get scaling property center + * @test: The KUnit test context + */ +static void dm_test_get_property_scaling_center(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0; + + ctx->new_state->scaling = RMX_CENTER; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, (int)DRM_MODE_SCALE_CENTER); +} + +/** + * dm_test_get_property_scaling_aspect - Test get scaling property aspect + * @test: The KUnit test context + */ +static void dm_test_get_property_scaling_aspect(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0; + + ctx->new_state->scaling = RMX_ASPECT; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, (int)DRM_MODE_SCALE_ASPECT); +} + +/** + * dm_test_get_property_scaling_full - Test get scaling property fullscreen + * @test: The KUnit test context + */ +static void dm_test_get_property_scaling_full(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0; + + ctx->new_state->scaling = RMX_FULL; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, (int)DRM_MODE_SCALE_FULLSCREEN); +} + +/** + * dm_test_get_property_scaling_off - Test get scaling property off/none + * @test: The KUnit test context + */ +static void dm_test_get_property_scaling_off(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0; + + ctx->new_state->scaling = RMX_OFF; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->scaling_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, (int)DRM_MODE_SCALE_NONE); +} + +/** + * dm_test_get_property_underscan_borders - Test get underscan borders/enable + * @test: The KUnit test context + */ +static void dm_test_get_property_underscan_borders(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0; + + ctx->new_state->underscan_hborder = 12; + ctx->new_state->underscan_vborder = 34; + ctx->new_state->underscan_enable = true; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->hborder_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, 12); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->vborder_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, 34); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->underscan_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, 1); +} + +/** + * dm_test_get_property_abm_sysfs_allowed - Test get abm returns sysfs control + * @test: The KUnit test context + */ +static void dm_test_get_property_abm_sysfs_allowed(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0; + + ctx->new_state->abm_sysfs_forbidden = false; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->abm_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, (int)ABM_SYSFS_CONTROL); +} + +/** + * dm_test_get_property_abm_level - Test get abm returns level when forbidden + * @test: The KUnit test context + */ +static void dm_test_get_property_abm_level(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0; + + ctx->new_state->abm_sysfs_forbidden = true; + ctx->new_state->abm_level = 2; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->abm_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, 2); +} + +/** + * dm_test_get_property_abm_disabled_zero - Test get abm returns 0 when disabled + * @test: The KUnit test context + */ +static void dm_test_get_property_abm_disabled_zero(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + uint64_t val = 0xdead; + + ctx->new_state->abm_sysfs_forbidden = true; + ctx->new_state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE; + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + ctx->abm_prop, &val), 0); + KUNIT_EXPECT_EQ(test, (int)val, 0); +} + +/** + * dm_test_get_property_unknown - Test get unknown property returns -EINVAL + * @test: The KUnit test context + */ +static void dm_test_get_property_unknown(struct kunit *test) +{ + struct dm_test_prop_ctx *ctx = dm_test_prop_ctx_alloc(test); + struct drm_property *other; + uint64_t val = 0; + + other = kunit_kzalloc(test, sizeof(*other), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, other); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_connector_atomic_get_property( + ctx->connector, &ctx->new_state->base, + other, &val), -EINVAL); +} + +/* Tests for amdgpu_dm_get_highest_refresh_rate_mode() */ + +/** + * dm_test_highest_refresh_writeback_null - Test writeback connector returns NULL + * @test: The KUnit test context + */ +static void dm_test_highest_refresh_writeback_null(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + aconnector->base.connector_type = DRM_MODE_CONNECTOR_WRITEBACK; + KUNIT_EXPECT_NULL(test, amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false)); +} + +/** + * dm_test_highest_refresh_cached_base - Test cached freesync_vid_base is returned + * @test: The KUnit test context + */ +static void dm_test_highest_refresh_cached_base(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + aconnector->base.connector_type = DRM_MODE_CONNECTOR_HDMIA; + aconnector->freesync_vid_base.clock = 148500; + + KUNIT_EXPECT_PTR_EQ(test, amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false), + &aconnector->freesync_vid_base); +} + +/** + * dm_test_highest_refresh_preferred_mode - Test preferred mode is selected + * @test: The KUnit test context + */ +static void dm_test_highest_refresh_preferred_mode(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_display_mode *mode; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + mode = kunit_kzalloc(test, sizeof(*mode), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, mode); + + aconnector->base.connector_type = DRM_MODE_CONNECTOR_HDMIA; + INIT_LIST_HEAD(&aconnector->base.modes); + + mode->type = DRM_MODE_TYPE_PREFERRED; + mode->clock = 148500; + mode->hdisplay = 1920; + mode->vdisplay = 1080; + mode->htotal = 2200; + mode->vtotal = 1125; + list_add_tail(&mode->head, &aconnector->base.modes); + + KUNIT_EXPECT_PTR_EQ(test, amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false), + mode); +} + +/* Tests for amdgpu_dm_is_freesync_video_mode() */ + +/** + * dm_test_is_freesync_video_mode_null_mode - Test NULL mode returns false + * @test: The KUnit test context + */ +static void dm_test_is_freesync_video_mode_null_mode(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + aconnector->base.connector_type = DRM_MODE_CONNECTOR_HDMIA; + aconnector->freesync_vid_base.clock = 148500; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_freesync_video_mode(NULL, aconnector)); +} + +/** + * dm_test_is_freesync_video_mode_match - Test matching mode returns true + * @test: The KUnit test context + */ +static void dm_test_is_freesync_video_mode_match(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_display_mode candidate = {}; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + /* Cached high mode acts as reference */ + aconnector->base.connector_type = DRM_MODE_CONNECTOR_HDMIA; + aconnector->freesync_vid_base.clock = 148500; + aconnector->freesync_vid_base.hdisplay = 1920; + aconnector->freesync_vid_base.vdisplay = 1080; + aconnector->freesync_vid_base.hsync_start = 2008; + aconnector->freesync_vid_base.hsync_end = 2052; + aconnector->freesync_vid_base.htotal = 2200; + aconnector->freesync_vid_base.vsync_start = 1084; + aconnector->freesync_vid_base.vsync_end = 1089; + aconnector->freesync_vid_base.vtotal = 1125; + + candidate.clock = 148500; + candidate.hdisplay = 1920; + candidate.vdisplay = 1080; + candidate.hsync_start = 2008; + candidate.hsync_end = 2052; + candidate.htotal = 2200; + candidate.vsync_start = 1084; + candidate.vsync_end = 1089; + candidate.vtotal = 1125; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_freesync_video_mode(&candidate, aconnector)); +} + +/** + * dm_test_is_freesync_video_mode_no_match - Test mismatched mode returns false + * @test: The KUnit test context + */ +static void dm_test_is_freesync_video_mode_no_match(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_display_mode candidate = {}; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + aconnector->base.connector_type = DRM_MODE_CONNECTOR_HDMIA; + aconnector->freesync_vid_base.clock = 148500; + aconnector->freesync_vid_base.hdisplay = 1920; + aconnector->freesync_vid_base.vdisplay = 1080; + aconnector->freesync_vid_base.htotal = 2200; + aconnector->freesync_vid_base.vtotal = 1125; + + /* Different resolution → not a freesync video mode */ + candidate.clock = 148500; + candidate.hdisplay = 1280; + candidate.vdisplay = 720; + candidate.htotal = 1650; + candidate.vtotal = 750; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_freesync_video_mode(&candidate, aconnector)); +} + +static struct kunit_case amdgpu_dm_connector_tests[] = { + /* get_subconnector_type */ + KUNIT_CASE(dm_test_subconnector_type_none), + KUNIT_CASE(dm_test_subconnector_type_vga), + KUNIT_CASE(dm_test_subconnector_type_dvi_converter), + KUNIT_CASE(dm_test_subconnector_type_dvi_dongle), + KUNIT_CASE(dm_test_subconnector_type_hdmi_converter), + KUNIT_CASE(dm_test_subconnector_type_hdmi_dongle), + KUNIT_CASE(dm_test_subconnector_type_mismatched), + KUNIT_CASE(dm_test_subconnector_type_default_unknown), + /* get_output_content_type */ + KUNIT_CASE(dm_test_content_type_no_data), + KUNIT_CASE(dm_test_content_type_graphics), + KUNIT_CASE(dm_test_content_type_photo), + KUNIT_CASE(dm_test_content_type_cinema), + KUNIT_CASE(dm_test_content_type_game), + KUNIT_CASE(dm_test_content_type_unknown_defaults_no_data), + /* adjust_colour_depth_from_display_info */ + KUNIT_CASE(dm_test_adjust_colour_depth_fits_at_888), + KUNIT_CASE(dm_test_adjust_colour_depth_reduces_to_888), + KUNIT_CASE(dm_test_adjust_colour_depth_10bpc_passes), + KUNIT_CASE(dm_test_adjust_colour_depth_420_halves_clk), + KUNIT_CASE(dm_test_adjust_colour_depth_reduces_12bpc_to_10bpc), + KUNIT_CASE(dm_test_adjust_colour_depth_16bpc_no_fallback), + KUNIT_CASE(dm_test_adjust_colour_depth_none_fits), + KUNIT_CASE(dm_test_adjust_colour_depth_invalid_depth), + /* amdgpu_dm_get_output_color_space */ + KUNIT_CASE(dm_test_output_color_space_default_rgb_full), + KUNIT_CASE(dm_test_output_color_space_default_rgb_limited), + KUNIT_CASE(dm_test_output_color_space_default_ycbcr709), + KUNIT_CASE(dm_test_output_color_space_default_ycbcr601_limited), + KUNIT_CASE(dm_test_output_color_space_bt601_y_only), + KUNIT_CASE(dm_test_output_color_space_bt601), + KUNIT_CASE(dm_test_output_color_space_bt709), + KUNIT_CASE(dm_test_output_color_space_bt709_y_only), + KUNIT_CASE(dm_test_output_color_space_oprgb), + KUNIT_CASE(dm_test_output_color_space_bt2020_rgb), + KUNIT_CASE(dm_test_output_color_space_bt2020_ycc), + /* Tests for amdgpu_dm_convert_dc_color_depth_into_bpc */ + KUNIT_CASE(dm_test_convert_color_depth_bpc_mappings), + KUNIT_CASE(dm_test_convert_color_depth_bpc_unknown), + /* amdgpu_dm_convert_color_depth_from_display_info */ + KUNIT_CASE(dm_test_color_depth_from_info_bpc8), + KUNIT_CASE(dm_test_color_depth_from_info_bpc10), + KUNIT_CASE(dm_test_color_depth_from_info_zero_bpc_defaults_888), + KUNIT_CASE(dm_test_color_depth_from_info_requested_bpc_caps), + KUNIT_CASE(dm_test_color_depth_from_info_y420_default), + KUNIT_CASE(dm_test_color_depth_from_info_y420_10bpc), + KUNIT_CASE(dm_test_color_depth_from_info_y420_12bpc), + KUNIT_CASE(dm_test_color_depth_from_info_y420_16bpc), + KUNIT_CASE(dm_test_color_depth_from_info_requested_odd_bpc), + KUNIT_CASE(dm_test_color_depth_from_info_unsupported_bpc), + /* to_drm_connector_type */ + KUNIT_CASE(dm_test_to_connector_type_hdmi), + KUNIT_CASE(dm_test_to_connector_type_edp), + KUNIT_CASE(dm_test_to_connector_type_lvds), + KUNIT_CASE(dm_test_to_connector_type_rgb), + KUNIT_CASE(dm_test_to_connector_type_dp), + KUNIT_CASE(dm_test_to_connector_type_dp_mst), + KUNIT_CASE(dm_test_to_connector_type_dvi_dvii), + KUNIT_CASE(dm_test_to_connector_type_dual_link_dvii), + KUNIT_CASE(dm_test_to_connector_type_dvi_dvid), + KUNIT_CASE(dm_test_to_connector_type_virtual), + KUNIT_CASE(dm_test_to_connector_type_unknown), + /* is_duplicate_mode */ + KUNIT_CASE(dm_test_is_duplicate_mode_empty_list), + KUNIT_CASE(dm_test_is_duplicate_mode_match), + KUNIT_CASE(dm_test_is_duplicate_mode_no_match), + KUNIT_CASE(dm_test_is_duplicate_mode_same_size_different_clock), + /* amdgpu_dm_get_encoder_crtc_mask */ + KUNIT_CASE(dm_test_encoder_crtc_mask_1), + KUNIT_CASE(dm_test_encoder_crtc_mask_2), + KUNIT_CASE(dm_test_encoder_crtc_mask_3), + KUNIT_CASE(dm_test_encoder_crtc_mask_4), + KUNIT_CASE(dm_test_encoder_crtc_mask_5), + KUNIT_CASE(dm_test_encoder_crtc_mask_6), + KUNIT_CASE(dm_test_encoder_crtc_mask_default), + /* get_aspect_ratio */ + KUNIT_CASE(dm_test_aspect_ratio_no_data), + KUNIT_CASE(dm_test_aspect_ratio_4_3), + KUNIT_CASE(dm_test_aspect_ratio_16_9), + KUNIT_CASE(dm_test_aspect_ratio_64_27), + KUNIT_CASE(dm_test_aspect_ratio_256_135), + /* decide_crtc_timing_for_drm_display_mode */ + KUNIT_CASE(dm_test_decide_crtc_timing_scale_enabled), + KUNIT_CASE(dm_test_decide_crtc_timing_matching_mode), + KUNIT_CASE(dm_test_decide_crtc_timing_no_copy), + KUNIT_CASE(dm_test_decide_crtc_timing_no_crtc_clock), + /* amdgpu_dm_connector_funcs_reset */ + KUNIT_CASE(dm_test_funcs_reset_sets_defaults), + KUNIT_CASE(dm_test_funcs_reset_edp_abm_level), + KUNIT_CASE(dm_test_funcs_reset_edp_abm_disabled), + /* amdgpu_dm_connector_atomic_duplicate_state */ + KUNIT_CASE(dm_test_atomic_dup_state_copies_fields), + /* amdgpu_dm_fill_hdr_info_packet */ + KUNIT_CASE(dm_test_fill_hdr_null_metadata), + KUNIT_CASE(dm_test_fill_hdr_zeroes_output), + /* amdgpu_dm_connector_atomic_set_property */ + KUNIT_CASE(dm_test_set_property_scaling_center), + KUNIT_CASE(dm_test_set_property_scaling_aspect), + KUNIT_CASE(dm_test_set_property_scaling_fullscreen), + KUNIT_CASE(dm_test_set_property_scaling_none), + KUNIT_CASE(dm_test_set_property_scaling_unchanged), + KUNIT_CASE(dm_test_set_property_underscan_hborder), + KUNIT_CASE(dm_test_set_property_underscan_vborder), + KUNIT_CASE(dm_test_set_property_underscan_enable), + KUNIT_CASE(dm_test_set_property_abm_sysfs_control), + KUNIT_CASE(dm_test_set_property_abm_level_off), + KUNIT_CASE(dm_test_set_property_abm_level_value), + KUNIT_CASE(dm_test_set_property_unknown), + /* amdgpu_dm_connector_atomic_get_property */ + KUNIT_CASE(dm_test_get_property_scaling_center), + KUNIT_CASE(dm_test_get_property_scaling_aspect), + KUNIT_CASE(dm_test_get_property_scaling_full), + KUNIT_CASE(dm_test_get_property_scaling_off), + KUNIT_CASE(dm_test_get_property_underscan_borders), + KUNIT_CASE(dm_test_get_property_abm_sysfs_allowed), + KUNIT_CASE(dm_test_get_property_abm_level), + KUNIT_CASE(dm_test_get_property_abm_disabled_zero), + KUNIT_CASE(dm_test_get_property_unknown), + /* amdgpu_dm_get_highest_refresh_rate_mode */ + KUNIT_CASE(dm_test_highest_refresh_writeback_null), + KUNIT_CASE(dm_test_highest_refresh_cached_base), + KUNIT_CASE(dm_test_highest_refresh_preferred_mode), + /* amdgpu_dm_is_freesync_video_mode */ + KUNIT_CASE(dm_test_is_freesync_video_mode_null_mode), + KUNIT_CASE(dm_test_is_freesync_video_mode_match), + KUNIT_CASE(dm_test_is_freesync_video_mode_no_match), + {} +}; + +static struct kunit_suite amdgpu_dm_connector_test_suite = { + .name = "amdgpu_dm_connector", + .test_cases = amdgpu_dm_connector_tests, +}; + +kunit_test_suite(amdgpu_dm_connector_test_suite); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_connector"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c index bba8b1a8fa1c..a6fd3a6fd803 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crc_test.c @@ -95,17 +95,139 @@ static void dm_test_is_valid_crc_source(struct kunit *test) KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_valid_crc_source(AMDGPU_DM_PIPE_CRC_SOURCE_INVALID)); } +/** + * dm_test_need_dp_aux() - Test dm_need_dp_aux(). + * @test: KUnit test context. + * + * Verifies that dm_need_dp_aux() returns true when the transition starts or + * stops a DPRX CRC source (requiring the DP AUX handle), and false for + * non-DPRX transitions such as CRTC or NONE→NONE. + */ +static void dm_test_need_dp_aux(struct kunit *test) +{ + /* Starting a DPRX source always needs AUX, regardless of current source */ + KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); + KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_CRTC)); + KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); + + /* Stopping a DPRX source (NONE requested, DPRX was active) needs AUX */ + KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX)); + KUNIT_EXPECT_TRUE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER)); + + /* CRTC transitions do not need AUX */ + KUNIT_EXPECT_FALSE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); + KUNIT_EXPECT_FALSE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_CRTC)); + KUNIT_EXPECT_FALSE(test, dm_need_dp_aux(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); +} + +/** + * dm_test_crc_source_should_start_dprx() - Test dm_crc_source_should_start_dprx(). + * @test: KUnit test context. + * + * Verifies that dm_crc_source_should_start_dprx() returns true only when CRC + * is transitioning from off (!enabled) to a DPRX source (enable && + * is_dprx(source)), and false for all other combinations including + * already-enabled or non-DPRX targets. + */ +static void dm_test_crc_source_should_start_dprx(struct kunit *test) +{ + /* CRC off → DPRX: should start */ + KUNIT_EXPECT_TRUE(test, + dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); + KUNIT_EXPECT_TRUE(test, + dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); + + /* CRC already on (any source) → DPRX: should NOT start (already enabled) */ + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_CRTC)); + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX)); + + /* CRC off → CRTC: not a DPRX start */ + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_CRTC, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); + + /* Disabling: should not start */ + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_start_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX)); +} + +/** + * dm_test_crc_source_should_stop_dprx() - Test dm_crc_source_should_stop_dprx(). + * @test: KUnit test context. + * + * Verifies that dm_crc_source_should_stop_dprx() returns true only when CRC + * is transitioning from a DPRX source (enabled && is_dprx(cur_crc_src)) to + * off (!enable), and false for non-DPRX disables, DPRX starts, and no-op + * transitions. + */ +static void dm_test_crc_source_should_stop_dprx(struct kunit *test) +{ + /* DPRX → off: should stop */ + KUNIT_EXPECT_TRUE(test, + dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX)); + KUNIT_EXPECT_TRUE(test, + dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX_DITHER)); + + /* CRTC → off: not a DPRX stop */ + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_CRTC)); + + /* off → DPRX: not a stop */ + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); + + /* DPRX → DPRX: no transition, not a stop */ + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_DPRX, + AMDGPU_DM_PIPE_CRC_SOURCE_DPRX)); + + /* off → off: not a stop */ + KUNIT_EXPECT_FALSE(test, + dm_crc_source_should_stop_dprx(AMDGPU_DM_PIPE_CRC_SOURCE_NONE, + AMDGPU_DM_PIPE_CRC_SOURCE_NONE)); +} + static struct kunit_case dm_crc_test_cases[] = { + /* dm_parse_crc_source() */ KUNIT_CASE(dm_test_parse_crc_source_none), KUNIT_CASE(dm_test_parse_crc_source_crtc), KUNIT_CASE(dm_test_parse_crc_source_dprx), KUNIT_CASE(dm_test_parse_crc_source_crtc_dither), KUNIT_CASE(dm_test_parse_crc_source_dprx_dither), KUNIT_CASE(dm_test_parse_crc_source_invalid), + /* dm_is_crc_source_crtc() */ KUNIT_CASE(dm_test_is_crc_source_crtc), + /* dm_is_crc_source_dprx() */ KUNIT_CASE(dm_test_is_crc_source_dprx), + /* dm_need_crc_dither() */ KUNIT_CASE(dm_test_need_crc_dither), + /* amdgpu_dm_is_valid_crc_source() */ KUNIT_CASE(dm_test_is_valid_crc_source), + /* dm_need_dp_aux() */ + KUNIT_CASE(dm_test_need_dp_aux), + /* dm_crc_source_should_start_dprx() */ + KUNIT_CASE(dm_test_crc_source_should_start_dprx), + /* dm_crc_source_should_stop_dprx() */ + KUNIT_CASE(dm_test_crc_source_should_stop_dprx), {} }; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c new file mode 100644 index 000000000000..0edaf969f16b --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_crtc_test.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_crtc.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_crtc.h" +#include "amdgpu_dm_kunit_test_helpers.h" +#include "amdgpu_dm_irq_params.h" + +/* Tests for amdgpu_dm_crtc_modeset_required() */ + +/** + * dm_test_crtc_modeset_required_active_mode_changed - Test Crtc modeset required active mode changed + * @test: The KUnit test context + */ +static void dm_test_crtc_modeset_required_active_mode_changed(struct kunit *test) +{ + struct drm_crtc_state state = {}; + + state.active = true; + state.mode_changed = true; + + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_crtc_modeset_required(&state, NULL, NULL)); +} + +/** + * dm_test_crtc_modeset_required_active_active_changed - Test Crtc modeset required active active changed + * @test: The KUnit test context + */ +static void dm_test_crtc_modeset_required_active_active_changed(struct kunit *test) +{ + struct drm_crtc_state state = {}; + + state.active = true; + state.active_changed = true; + + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_crtc_modeset_required(&state, NULL, NULL)); +} + +/** + * dm_test_crtc_modeset_required_active_connectors_changed - Test Crtc modeset required active connectors changed + * @test: The KUnit test context + */ +static void dm_test_crtc_modeset_required_active_connectors_changed(struct kunit *test) +{ + struct drm_crtc_state state = {}; + + state.active = true; + state.connectors_changed = true; + + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_crtc_modeset_required(&state, NULL, NULL)); +} + +/** + * dm_test_crtc_modeset_required_inactive - Test Crtc modeset required inactive + * @test: The KUnit test context + */ +static void dm_test_crtc_modeset_required_inactive(struct kunit *test) +{ + struct drm_crtc_state state = {}; + + state.active = false; + state.mode_changed = true; + + KUNIT_EXPECT_FALSE(test, + amdgpu_dm_crtc_modeset_required(&state, NULL, NULL)); +} + +/** + * dm_test_crtc_modeset_required_no_changes - Test Crtc modeset required no changes + * @test: The KUnit test context + */ +static void dm_test_crtc_modeset_required_no_changes(struct kunit *test) +{ + struct drm_crtc_state state = {}; + + state.active = true; + state.mode_changed = false; + state.active_changed = false; + state.connectors_changed = false; + + KUNIT_EXPECT_FALSE(test, + amdgpu_dm_crtc_modeset_required(&state, NULL, NULL)); +} + +/* Tests for amdgpu_dm_crtc_vrr_active_irq() */ + +/** + * dm_test_crtc_vrr_active_irq_variable - Test Crtc vrr active irq variable + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_irq_variable(struct kunit *test) +{ + struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + + acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_crtc_vrr_active_irq(acrtc)); +} + +/** + * dm_test_crtc_vrr_active_irq_fixed - Test Crtc vrr active irq fixed + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_irq_fixed(struct kunit *test) +{ + struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + + acrtc->dm_irq_params.freesync_config.state = VRR_STATE_ACTIVE_FIXED; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_crtc_vrr_active_irq(acrtc)); +} + +/** + * dm_test_crtc_vrr_active_irq_inactive - Test Crtc vrr active irq inactive + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_irq_inactive(struct kunit *test) +{ + struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + + acrtc->dm_irq_params.freesync_config.state = VRR_STATE_INACTIVE; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_vrr_active_irq(acrtc)); +} + +/** + * dm_test_crtc_vrr_active_irq_disabled - Test Crtc vrr active irq disabled + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_irq_disabled(struct kunit *test) +{ + struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + + acrtc->dm_irq_params.freesync_config.state = VRR_STATE_DISABLED; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_vrr_active_irq(acrtc)); +} + +/** + * dm_test_crtc_vrr_active_irq_unsupported - Test Crtc vrr active irq unsupported + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_irq_unsupported(struct kunit *test) +{ + struct amdgpu_crtc *acrtc = kunit_kzalloc(test, sizeof(*acrtc), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + + acrtc->dm_irq_params.freesync_config.state = VRR_STATE_UNSUPPORTED; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_vrr_active_irq(acrtc)); +} + +/* Tests for amdgpu_dm_crtc_vrr_active() */ + +/** + * dm_test_crtc_vrr_active_variable - Test Crtc vrr active variable + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_variable(struct kunit *test) +{ + struct dm_crtc_state *dm_state = kunit_kzalloc(test, + sizeof(*dm_state), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + + dm_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_crtc_vrr_active(dm_state)); +} + +/** + * dm_test_crtc_vrr_active_fixed - Test Crtc vrr active fixed + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_fixed(struct kunit *test) +{ + struct dm_crtc_state *dm_state = kunit_kzalloc(test, + sizeof(*dm_state), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + + dm_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_crtc_vrr_active(dm_state)); +} + +/** + * dm_test_crtc_vrr_active_inactive - Test Crtc vrr active inactive + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_inactive(struct kunit *test) +{ + struct dm_crtc_state *dm_state = kunit_kzalloc(test, + sizeof(*dm_state), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + + dm_state->freesync_config.state = VRR_STATE_INACTIVE; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_vrr_active(dm_state)); +} + +/** + * dm_test_crtc_vrr_active_disabled - Test Crtc vrr active disabled + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_disabled(struct kunit *test) +{ + struct dm_crtc_state *dm_state = kunit_kzalloc(test, + sizeof(*dm_state), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + + dm_state->freesync_config.state = VRR_STATE_DISABLED; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_vrr_active(dm_state)); +} + +/** + * dm_test_crtc_vrr_active_unsupported - Test Crtc vrr active unsupported + * @test: The KUnit test context + */ +static void dm_test_crtc_vrr_active_unsupported(struct kunit *test) +{ + struct dm_crtc_state *dm_state = kunit_kzalloc(test, + sizeof(*dm_state), + GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_state); + + dm_state->freesync_config.state = VRR_STATE_UNSUPPORTED; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_crtc_vrr_active(dm_state)); +} + +/* Tests for amdgpu_dm_is_headless() */ + +static void dm_test_add_connector(struct drm_device *dev, + struct drm_connector *connector, + int connector_type, + enum drm_connector_status status) +{ + INIT_LIST_HEAD(&connector->head); + kref_init(&connector->base.refcount); + connector->connector_type = connector_type; + connector->status = status; + list_add_tail(&connector->head, &dev->mode_config.connector_list); +} + +/** + * dm_test_crtc_is_headless_null_adev - Test Crtc is headless null adev + * @test: The KUnit test context + */ +static void dm_test_crtc_is_headless_null_adev(struct kunit *test) +{ + KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_headless(NULL)); +} + +/** + * dm_test_crtc_is_headless_no_connectors - Test Crtc is headless no connectors + * @test: The KUnit test context + */ +static void dm_test_crtc_is_headless_no_connectors(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct drm_device *dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + INIT_LIST_HEAD(&dev->mode_config.connector_list); + spin_lock_init(&dev->mode_config.connector_list_lock); + adev->dm.ddev = dev; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_headless(adev)); +} + +/** + * dm_test_crtc_is_headless_writeback_only - Test Crtc is headless writeback only + * @test: The KUnit test context + */ +static void dm_test_crtc_is_headless_writeback_only(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct drm_device *dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + struct drm_connector *wb = kunit_kzalloc(test, sizeof(*wb), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb); + + INIT_LIST_HEAD(&dev->mode_config.connector_list); + spin_lock_init(&dev->mode_config.connector_list_lock); + adev->dm.ddev = dev; + + dm_test_add_connector(dev, wb, DRM_MODE_CONNECTOR_WRITEBACK, + connector_status_connected); + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_headless(adev)); +} + +/** + * dm_test_crtc_is_headless_disconnected_display - Test Crtc is headless disconnected display + * @test: The KUnit test context + */ +static void dm_test_crtc_is_headless_disconnected_display(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct drm_device *dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display); + + INIT_LIST_HEAD(&dev->mode_config.connector_list); + spin_lock_init(&dev->mode_config.connector_list_lock); + adev->dm.ddev = dev; + + dm_test_add_connector(dev, display, DRM_MODE_CONNECTOR_HDMIA, + connector_status_disconnected); + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_headless(adev)); +} + +/** + * dm_test_crtc_is_headless_connected_display - Test Crtc is headless connected display + * @test: The KUnit test context + */ +static void dm_test_crtc_is_headless_connected_display(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct drm_device *dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display); + + INIT_LIST_HEAD(&dev->mode_config.connector_list); + spin_lock_init(&dev->mode_config.connector_list_lock); + adev->dm.ddev = dev; + + dm_test_add_connector(dev, display, DRM_MODE_CONNECTOR_HDMIA, + connector_status_connected); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_headless(adev)); +} + +/** + * dm_test_crtc_is_headless_mixed_connectors - Test headless skips WB and finds display + * @test: The KUnit test context + */ +static void dm_test_crtc_is_headless_mixed_connectors(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct drm_device *dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + struct drm_connector *wb = kunit_kzalloc(test, sizeof(*wb), GFP_KERNEL); + struct drm_connector *display = kunit_kzalloc(test, sizeof(*display), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, wb); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, display); + + INIT_LIST_HEAD(&dev->mode_config.connector_list); + spin_lock_init(&dev->mode_config.connector_list_lock); + adev->dm.ddev = dev; + + dm_test_add_connector(dev, wb, DRM_MODE_CONNECTOR_WRITEBACK, + connector_status_connected); + dm_test_add_connector(dev, display, DRM_MODE_CONNECTOR_DisplayPort, + connector_status_connected); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_headless(adev)); +} + +/* Tests for amdgpu_dm_crtc_helper_mode_fixup() */ + +/** + * dm_test_crtc_helper_mode_fixup_returns_true - Test mode_fixup accepts mode + * @test: The KUnit test context + */ +static void dm_test_crtc_helper_mode_fixup_returns_true(struct kunit *test) +{ + struct drm_display_mode mode = { 0 }; + struct drm_display_mode adjusted_mode = { 0 }; + + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_crtc_helper_mode_fixup(NULL, &mode, &adjusted_mode)); +} + +/* Tests for amdgpu_dm_crtc_set_vupdate_irq() */ + +/** + * dm_test_crtc_set_vupdate_irq_no_otg - Test vupdate irq with unassigned OTG + * @test: The KUnit test context + * + * When the CRTC has no OTG instance assigned (otg_inst == -1) the function + * must return 0 immediately without touching the DC interrupt state. + */ +static void dm_test_crtc_set_vupdate_irq_no_otg(struct kunit *test) +{ + struct amdgpu_crtc *acrtc; + struct amdgpu_device *adev; + + adev = dm_kunit_alloc_adev(test); + + acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + + acrtc->base.dev = &adev->ddev; + acrtc->otg_inst = -1; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, true), 0); + KUNIT_EXPECT_EQ(test, amdgpu_dm_crtc_set_vupdate_irq(&acrtc->base, false), 0); +} + +/* Tests for idle_create_workqueue() */ + +/** + * dm_test_idle_create_workqueue - Test idle workqueue creation + * @test: The KUnit test context + * + * Verify that idle_create_workqueue() allocates an idle workqueue tied to the + * device's display manager and initializes it in a disabled, non-running state. + */ +static void dm_test_idle_create_workqueue(struct kunit *test) +{ + struct amdgpu_device *adev; + struct idle_workqueue *idle_work; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + idle_work = idle_create_workqueue(adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, idle_work); + + KUNIT_EXPECT_PTR_EQ(test, idle_work->dm, &adev->dm); + KUNIT_EXPECT_FALSE(test, idle_work->enable); + KUNIT_EXPECT_FALSE(test, idle_work->running); + + kfree(idle_work); +} + +static struct kunit_case amdgpu_dm_crtc_tests[] = { + /* amdgpu_dm_crtc_modeset_required */ + KUNIT_CASE(dm_test_crtc_modeset_required_active_mode_changed), + KUNIT_CASE(dm_test_crtc_modeset_required_active_active_changed), + KUNIT_CASE(dm_test_crtc_modeset_required_active_connectors_changed), + KUNIT_CASE(dm_test_crtc_modeset_required_inactive), + KUNIT_CASE(dm_test_crtc_modeset_required_no_changes), + /* amdgpu_dm_crtc_vrr_active_irq */ + KUNIT_CASE(dm_test_crtc_vrr_active_irq_variable), + KUNIT_CASE(dm_test_crtc_vrr_active_irq_fixed), + KUNIT_CASE(dm_test_crtc_vrr_active_irq_inactive), + KUNIT_CASE(dm_test_crtc_vrr_active_irq_disabled), + KUNIT_CASE(dm_test_crtc_vrr_active_irq_unsupported), + /* amdgpu_dm_crtc_vrr_active */ + KUNIT_CASE(dm_test_crtc_vrr_active_variable), + KUNIT_CASE(dm_test_crtc_vrr_active_fixed), + KUNIT_CASE(dm_test_crtc_vrr_active_inactive), + KUNIT_CASE(dm_test_crtc_vrr_active_disabled), + KUNIT_CASE(dm_test_crtc_vrr_active_unsupported), + /* amdgpu_dm_is_headless */ + KUNIT_CASE(dm_test_crtc_is_headless_null_adev), + KUNIT_CASE(dm_test_crtc_is_headless_no_connectors), + KUNIT_CASE(dm_test_crtc_is_headless_writeback_only), + KUNIT_CASE(dm_test_crtc_is_headless_disconnected_display), + KUNIT_CASE(dm_test_crtc_is_headless_connected_display), + KUNIT_CASE(dm_test_crtc_is_headless_mixed_connectors), + /* amdgpu_dm_crtc_helper_mode_fixup */ + KUNIT_CASE(dm_test_crtc_helper_mode_fixup_returns_true), + /* amdgpu_dm_crtc_set_vupdate_irq */ + KUNIT_CASE(dm_test_crtc_set_vupdate_irq_no_otg), + /* idle_create_workqueue */ + KUNIT_CASE(dm_test_idle_create_workqueue), + {} +}; + +static struct kunit_suite amdgpu_dm_crtc_test_suite = { + .name = "amdgpu_dm_crtc", + .test_cases = amdgpu_dm_crtc_tests, +}; + +kunit_test_suite(amdgpu_dm_crtc_test_suite); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_crtc"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c new file mode 100644 index 000000000000..bf90ccfbf431 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_dmub_test.c @@ -0,0 +1,582 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_dmub.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include + +#include "dc.h" +#include "dc/inc/core_types.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "dmub/dmub_srv.h" +#include "amdgpu_dm_dmub.h" + +/* Tests for dm_register_dmub_notify_callback() */ + +static void dummy_callback(struct amdgpu_device *adev, + struct dmub_notification *notify) +{ +} + +/** + * dm_test_register_dmub_notify_callback_null_callback - Test null callback is rejected + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_null_callback(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev, + DMUB_NOTIFICATION_AUX_REPLY, NULL, false)); +} + +/** + * dm_test_register_dmub_notify_callback_type_out_of_range - Test out-of-range type is rejected + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_type_out_of_range(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_FALSE(test, dm_register_dmub_notify_callback(adev, + AMDGPU_DMUB_NOTIFICATION_MAX, dummy_callback, false)); +} + +/** + * dm_test_register_dmub_notify_callback_valid - Test Register dmub notify callback valid + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_valid(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev, + DMUB_NOTIFICATION_AUX_REPLY, dummy_callback, true)); + + KUNIT_EXPECT_TRUE(test, + adev->dm.dmub_callback[DMUB_NOTIFICATION_AUX_REPLY] == dummy_callback); + KUNIT_EXPECT_TRUE(test, + adev->dm.dmub_thread_offload[DMUB_NOTIFICATION_AUX_REPLY]); +} + +/** + * dm_test_register_dmub_notify_callback_offload_false - Test registration with offload disabled + * @test: The KUnit test context + */ +static void dm_test_register_dmub_notify_callback_offload_false(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_TRUE(test, dm_register_dmub_notify_callback(adev, + DMUB_NOTIFICATION_HPD, dummy_callback, false)); + + KUNIT_EXPECT_TRUE(test, + adev->dm.dmub_callback[DMUB_NOTIFICATION_HPD] == dummy_callback); + KUNIT_EXPECT_FALSE(test, + adev->dm.dmub_thread_offload[DMUB_NOTIFICATION_HPD]); +} + +/* Tests for dm_dmub_aux_setconfig_callback() */ + +/** + * dm_test_dmub_aux_setconfig_callback_copies_and_completes - Test copy and complete on AUX reply + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_copies_and_completes(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification *dm_notify; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = dm_notify; + + notify.type = DMUB_NOTIFICATION_AUX_REPLY; + notify.result = AUX_RET_SUCCESS; + notify.aux_reply.command = 0xA5; + notify.aux_reply.length = 3; + notify.aux_reply.data[0] = 0x11; + notify.aux_reply.data[1] = 0x22; + notify.aux_reply.data[2] = 0x33; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_EQ(test, dm_notify->type, notify.type); + KUNIT_EXPECT_EQ(test, dm_notify->result, notify.result); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.command, notify.aux_reply.command); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.length, notify.aux_reply.length); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.data[0], notify.aux_reply.data[0]); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.data[1], notify.aux_reply.data[1]); + KUNIT_EXPECT_EQ(test, dm_notify->aux_reply.data[2], notify.aux_reply.data[2]); + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/** + * dm_test_dmub_aux_setconfig_callback_non_aux_no_complete - Test non-AUX type skips completion + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_non_aux_no_complete(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification *dm_notify; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = dm_notify; + + notify.type = DMUB_NOTIFICATION_HPD; + notify.result = AUX_RET_ERROR_TIMEOUT; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_EQ(test, dm_notify->type, notify.type); + KUNIT_EXPECT_FALSE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/** + * dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify - Test AUX with NULL dm_notify + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = NULL; + + notify.type = DMUB_NOTIFICATION_AUX_REPLY; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/** + * dm_test_dmub_aux_setconfig_callback_set_config_reply - Test SET_CONFIG reply copies status + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_setconfig_callback_set_config_reply(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification *dm_notify; + struct dmub_notification notify = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dm_notify = kunit_kzalloc(test, sizeof(*dm_notify), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm_notify); + + init_completion(&adev->dm.dmub_aux_transfer_done); + adev->dm.dmub_notify = dm_notify; + + notify.type = DMUB_NOTIFICATION_SET_CONFIG_REPLY; + notify.sc_status = SET_CONFIG_RX_TIMEOUT; + + dm_dmub_aux_setconfig_callback(adev, ¬ify); + + KUNIT_EXPECT_EQ(test, dm_notify->type, notify.type); + KUNIT_EXPECT_EQ(test, dm_notify->sc_status, notify.sc_status); + KUNIT_EXPECT_FALSE(test, completion_done(&adev->dm.dmub_aux_transfer_done)); +} + +/* Tests for dm_dmub_aux_fused_io_callback() */ + +/** + * dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes - Test copy and complete + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification notify = {}; + struct dmub_cmd_fused_request *reply; + u32 reply_ddc_line; + u32 notify_ddc_line; + u32 reply_address; + u32 notify_address; + u32 reply_length; + u32 notify_length; + uint8_t ddc_line = 2; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + init_completion(&adev->dm.fused_io[ddc_line].replied); + + notify.fused_request.identifier = 0x34; + notify.fused_request.status = FUSED_REQUEST_STATUS_SUCCESS; + notify.fused_request.u.aux.ddc_line = ddc_line; + notify.fused_request.u.aux.address = 0x50; + notify.fused_request.u.aux.length = 4; + + dm_dmub_aux_fused_io_callback(adev, ¬ify); + + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.fused_io[ddc_line].replied)); + + reply = (struct dmub_cmd_fused_request *)adev->dm.fused_io[ddc_line].reply_data; + reply_ddc_line = reply->u.aux.ddc_line; + notify_ddc_line = notify.fused_request.u.aux.ddc_line; + reply_address = reply->u.aux.address; + notify_address = notify.fused_request.u.aux.address; + reply_length = reply->u.aux.length; + notify_length = notify.fused_request.u.aux.length; + + KUNIT_EXPECT_EQ(test, reply->identifier, notify.fused_request.identifier); + KUNIT_EXPECT_EQ(test, reply->status, notify.fused_request.status); + KUNIT_EXPECT_EQ(test, reply_ddc_line, notify_ddc_line); + KUNIT_EXPECT_EQ(test, reply_address, notify_address); + KUNIT_EXPECT_EQ(test, reply_length, notify_length); +} + +/** + * dm_test_dmub_aux_fused_io_callback_max_ddc_line - Test Dmub aux fused io callback max ddc line + * @test: The KUnit test context + */ +static void dm_test_dmub_aux_fused_io_callback_max_ddc_line(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dmub_notification notify = {}; + struct dmub_cmd_fused_request *reply; + u32 reply_ddc_line; + u32 notify_ddc_line; + uint8_t ddc_line; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + ddc_line = ARRAY_SIZE(adev->dm.fused_io) - 1; + init_completion(&adev->dm.fused_io[ddc_line].replied); + + notify.fused_request.identifier = 0x56; + notify.fused_request.status = FUSED_REQUEST_STATUS_SUCCESS; + notify.fused_request.u.aux.ddc_line = ddc_line; + notify.fused_request.u.aux.address = 0x50; + notify.fused_request.u.aux.length = 1; + + dm_dmub_aux_fused_io_callback(adev, ¬ify); + + KUNIT_EXPECT_TRUE(test, completion_done(&adev->dm.fused_io[ddc_line].replied)); + + reply = (struct dmub_cmd_fused_request *)adev->dm.fused_io[ddc_line].reply_data; + reply_ddc_line = reply->u.aux.ddc_line; + notify_ddc_line = notify.fused_request.u.aux.ddc_line; + + KUNIT_EXPECT_EQ(test, reply->identifier, notify.fused_request.identifier); + KUNIT_EXPECT_EQ(test, reply_ddc_line, notify_ddc_line); +} + +/* Tests for dm_get_default_ips_mode() */ + +/** + * dm_test_get_default_ips_mode_dcn35 - Test Get default ips mode dcn35 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_dcn35(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 0); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF); +} + +/** + * dm_test_get_default_ips_mode_dcn351 - Test Get default ips mode dcn351 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_dcn351(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 5, 1); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF); +} + +/** + * dm_test_get_default_ips_mode_dcn36 - Test Get default ips mode dcn36 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_dcn36(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 6, 0); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_RCG_IN_ACTIVE_IPS2_IN_OFF); +} + +/** + * dm_test_get_default_ips_mode_older_than_dcn35 - Test Get default ips mode older than dcn35 + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_older_than_dcn35(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(3, 2, 0); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_DISABLE_ALL); +} + +/** + * dm_test_get_default_ips_mode_newer_default - Test Get default ips mode newer default + * @test: The KUnit test context + */ +static void dm_test_get_default_ips_mode_newer_default(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + /* DCN 4.0.1 is >= 3.5 but has no explicit case, returns ENABLE */ + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 0, 1); + + KUNIT_EXPECT_EQ(test, dm_get_default_ips_mode(adev), + DMUB_IPS_ENABLE); +} + +/* Tests for dm_dmub_hw_init() */ + +/* + * Build an amdgpu_device with the minimal dc/res_pool pointers that + * dm_dmub_hw_init() and dm_dmub_hw_resume() dereference before their + * early-return checks. + */ +static struct amdgpu_device *dm_test_alloc_adev_with_dc(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct resource_pool *res_pool; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dc); + + res_pool = kunit_kzalloc(test, sizeof(*res_pool), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res_pool); + + dc->res_pool = res_pool; + adev->dm.dc = dc; + + return adev; +} + +/** + * dm_test_dmub_hw_init_no_dmub_srv - Test hw init returns 0 when DMUB unsupported + * @test: The KUnit test context + * + * When adev->dm.dmub_srv is NULL the ASIC does not support DMUB and + * dm_dmub_hw_init() should return 0 without touching the hardware. + */ +static void dm_test_dmub_hw_init_no_dmub_srv(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test); + + adev->dm.dmub_srv = NULL; + + KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), 0); +} + +/** + * dm_test_dmub_hw_init_no_fb_info - Test hw init fails without framebuffer info + * @test: The KUnit test context + * + * With a DMUB service present but no framebuffer info, dm_dmub_hw_init() + * should return -EINVAL. + */ +static void dm_test_dmub_hw_init_no_fb_info(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test); + struct dmub_srv *dmub_srv; + + dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + + adev->dm.dmub_srv = dmub_srv; + adev->dm.dmub_fb_info = NULL; + + KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL); +} + +/** + * dm_test_dmub_hw_init_no_firmware - Test hw init fails without firmware + * @test: The KUnit test context + * + * With a DMUB service and framebuffer info present but no firmware, + * dm_dmub_hw_init() should return -EINVAL. + */ +static void dm_test_dmub_hw_init_no_firmware(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test); + struct dmub_srv *dmub_srv; + struct dmub_srv_fb_info *fb_info; + + dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dmub_srv); + + fb_info = kunit_kzalloc(test, sizeof(*fb_info), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb_info); + + adev->dm.dmub_srv = dmub_srv; + adev->dm.dmub_fb_info = fb_info; + adev->dm.dmub_fw = NULL; + + KUNIT_EXPECT_EQ(test, dm_dmub_hw_init(adev), -EINVAL); +} + +/* Tests for dm_dmub_hw_resume() */ + +/** + * dm_test_dmub_hw_resume_no_dmub_srv - Test hw resume is a no-op when DMUB unsupported + * @test: The KUnit test context + * + * When adev->dm.dmub_srv is NULL, dm_dmub_hw_resume() should return early + * without dereferencing the (absent) DMUB service. + */ +static void dm_test_dmub_hw_resume_no_dmub_srv(struct kunit *test) +{ + struct amdgpu_device *adev = dm_test_alloc_adev_with_dc(test); + + adev->dm.dmub_srv = NULL; + + /* Must not crash. */ + dm_dmub_hw_resume(adev); +} + +/* Tests for dm_dmub_sw_init() */ + +/** + * dm_test_dmub_sw_init_unsupported_asic - Test sw init returns 0 for unsupported ASIC + * @test: The KUnit test context + * + * For an IP version with no DMUB support, dm_dmub_sw_init() should return 0 + * before attempting to access the firmware. + */ +static void dm_test_dmub_sw_init_unsupported_asic(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); + + KUNIT_EXPECT_EQ(test, dm_dmub_sw_init(adev), 0); +} + +/* Tests for dm_init_microcode() */ + +/** + * dm_test_init_microcode_unsupported_asic - Test microcode init returns 0 for unsupported ASIC + * @test: The KUnit test context + * + * For an IP version with no DMUB support, dm_init_microcode() should return 0 + * without requesting any firmware. + */ +static void dm_test_init_microcode_unsupported_asic(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(1, 0, 0); + + KUNIT_EXPECT_EQ(test, dm_init_microcode(adev), 0); +} + +static struct kunit_case amdgpu_dm_dmub_tests[] = { + /* dm_register_dmub_notify_callback() */ + KUNIT_CASE(dm_test_register_dmub_notify_callback_null_callback), + KUNIT_CASE(dm_test_register_dmub_notify_callback_type_out_of_range), + KUNIT_CASE(dm_test_register_dmub_notify_callback_valid), + KUNIT_CASE(dm_test_register_dmub_notify_callback_offload_false), + /* dm_dmub_aux_setconfig_callback() */ + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_copies_and_completes), + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_non_aux_no_complete), + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_aux_with_null_dm_notify), + KUNIT_CASE(dm_test_dmub_aux_setconfig_callback_set_config_reply), + /* dm_dmub_aux_fused_io_callback() */ + KUNIT_CASE(dm_test_dmub_aux_fused_io_callback_copies_reply_and_completes), + KUNIT_CASE(dm_test_dmub_aux_fused_io_callback_max_ddc_line), + /* dm_get_default_ips_mode() */ + KUNIT_CASE(dm_test_get_default_ips_mode_dcn35), + KUNIT_CASE(dm_test_get_default_ips_mode_dcn351), + KUNIT_CASE(dm_test_get_default_ips_mode_dcn36), + KUNIT_CASE(dm_test_get_default_ips_mode_older_than_dcn35), + KUNIT_CASE(dm_test_get_default_ips_mode_newer_default), + /* dm_dmub_hw_init() */ + KUNIT_CASE(dm_test_dmub_hw_init_no_dmub_srv), + KUNIT_CASE(dm_test_dmub_hw_init_no_fb_info), + KUNIT_CASE(dm_test_dmub_hw_init_no_firmware), + /* dm_dmub_hw_resume() */ + KUNIT_CASE(dm_test_dmub_hw_resume_no_dmub_srv), + /* dm_dmub_sw_init() */ + KUNIT_CASE(dm_test_dmub_sw_init_unsupported_asic), + /* dm_init_microcode() */ + KUNIT_CASE(dm_test_init_microcode_unsupported_asic), + {} +}; + +static struct kunit_suite amdgpu_dm_dmub_test_suite = { + .name = "amdgpu_dm_dmub", + .test_cases = amdgpu_dm_dmub_tests, +}; + +kunit_test_suite(amdgpu_dm_dmub_test_suite); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_dmub"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c index d03b606d27bc..619b4a80c82b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c @@ -12,11 +12,241 @@ static void dummy_work_fn(struct work_struct *work) {} +/* Tests for hdcp_get_content_protection_from_status() */ + +/** + * dm_test_hdcp_get_cp_disabled_returns_desired - HDCP off maps to DESIRED + * @test: KUnit test context + * + * When encryption status is HDCP_OFF, content_protection should be set + * to DESIRED and the function should return true to indicate an update. + */ +static void dm_test_hdcp_get_cp_disabled_returns_desired(struct kunit *test) +{ + unsigned int content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + bool update; + + update = hdcp_get_content_protection_from_status( + DRM_MODE_HDCP_CONTENT_TYPE0, + MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF, + &content_protection); + + KUNIT_EXPECT_TRUE(test, update); + KUNIT_EXPECT_EQ(test, content_protection, + DRM_MODE_CONTENT_PROTECTION_DESIRED); +} + +/** + * dm_test_hdcp_get_cp_type0_returns_enabled - TYPE0 with TYPE0_ON maps to ENABLED + * @test: KUnit test context + * + * When content type is TYPE0 and encryption status is at or below + * HDCP2_TYPE0_ON, content_protection should be set to ENABLED. + */ +static void dm_test_hdcp_get_cp_type0_returns_enabled(struct kunit *test) +{ + unsigned int content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + bool update; + + update = hdcp_get_content_protection_from_status( + DRM_MODE_HDCP_CONTENT_TYPE0, + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON, + &content_protection); + + KUNIT_EXPECT_TRUE(test, update); + KUNIT_EXPECT_EQ(test, content_protection, + DRM_MODE_CONTENT_PROTECTION_ENABLED); +} + +/** + * dm_test_hdcp_get_cp_type1_returns_enabled - TYPE1 with TYPE1_ON maps to ENABLED + * @test: KUnit test context + * + * When content type is TYPE1 and encryption status is exactly + * HDCP2_TYPE1_ON, content_protection should be set to ENABLED. + */ +static void dm_test_hdcp_get_cp_type1_returns_enabled(struct kunit *test) +{ + unsigned int content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + bool update; + + update = hdcp_get_content_protection_from_status( + DRM_MODE_HDCP_CONTENT_TYPE1, + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON, + &content_protection); + + KUNIT_EXPECT_TRUE(test, update); + KUNIT_EXPECT_EQ(test, content_protection, + DRM_MODE_CONTENT_PROTECTION_ENABLED); +} + +/** + * dm_test_hdcp_get_cp_type1_rejects_type0_status - TYPE1 rejects TYPE0_ON + * @test: KUnit test context + * + * When content type is TYPE1 but encryption status is only TYPE0_ON, + * the function should return false and leave content_protection unchanged. + */ +static void dm_test_hdcp_get_cp_type1_rejects_type0_status(struct kunit *test) +{ + unsigned int content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + bool update; + + update = hdcp_get_content_protection_from_status( + DRM_MODE_HDCP_CONTENT_TYPE1, + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE0_ON, + &content_protection); + + KUNIT_EXPECT_FALSE(test, update); + KUNIT_EXPECT_EQ(test, content_protection, + DRM_MODE_CONTENT_PROTECTION_UNDESIRED); +} + +/** + * dm_test_hdcp_get_cp_type0_rejects_type1_status - TYPE0 rejects TYPE1_ON + * @test: KUnit test context + * + * When content type is TYPE0 but encryption status exceeds the TYPE0_ON + * boundary (TYPE1_ON), the function should return false. + */ +static void dm_test_hdcp_get_cp_type0_rejects_type1_status(struct kunit *test) +{ + unsigned int content_protection = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + bool update; + + update = hdcp_get_content_protection_from_status( + DRM_MODE_HDCP_CONTENT_TYPE0, + MOD_HDCP_ENCRYPTION_STATUS_HDCP2_TYPE1_ON, + &content_protection); + + KUNIT_EXPECT_FALSE(test, update); + KUNIT_EXPECT_EQ(test, content_protection, + DRM_MODE_CONTENT_PROTECTION_UNDESIRED); +} + +/* Tests for hdcp_get_link_display_adjustments() */ + +/** + * dm_test_hdcp_get_adjustments_disable_authentication - disable path zeroes adjustments + * @test: KUnit test context + * + * When enable_encryption is false, display_adjust should disable + * authentication and all link_adjust fields should remain zeroed. + */ +static void dm_test_hdcp_get_adjustments_disable_authentication(struct kunit *test) +{ + struct mod_hdcp_link_adjustment link_adjust; + struct mod_hdcp_display_adjustment display_adjust; + unsigned int disable; + unsigned int hdcp1_disable; + unsigned int force_type; + + hdcp_get_link_display_adjustments(false, DRM_MODE_HDCP_CONTENT_TYPE0, + false, false, false, &link_adjust, &display_adjust); + disable = display_adjust.disable; + hdcp1_disable = link_adjust.hdcp1.disable; + force_type = link_adjust.hdcp2.force_type; + + KUNIT_EXPECT_EQ(test, disable, + MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION); + KUNIT_EXPECT_EQ(test, link_adjust.auth_delay, 0); + KUNIT_EXPECT_EQ(test, link_adjust.retry_limit, 0); + KUNIT_EXPECT_EQ(test, hdcp1_disable, 0); + KUNIT_EXPECT_EQ(test, force_type, 0); +} + +/** + * dm_test_hdcp_get_adjustments_type0_policy - TYPE0 enables HDCP1 and forces TYPE0 + * @test: KUnit test context + * + * When encryption is enabled with content TYPE0, hdcp1 should remain + * enabled, force_type should be TYPE_0, and sw_locality_fallback should + * be propagated from the input parameter. + */ +static void dm_test_hdcp_get_adjustments_type0_policy(struct kunit *test) +{ + struct mod_hdcp_link_adjustment link_adjust; + struct mod_hdcp_display_adjustment display_adjust; + unsigned int disable; + unsigned int hdcp1_disable; + unsigned int force_type; + + hdcp_get_link_display_adjustments(true, DRM_MODE_HDCP_CONTENT_TYPE0, + false, false, true, &link_adjust, &display_adjust); + disable = display_adjust.disable; + hdcp1_disable = link_adjust.hdcp1.disable; + force_type = link_adjust.hdcp2.force_type; + + KUNIT_EXPECT_EQ(test, disable, + MOD_HDCP_DISPLAY_NOT_DISABLE); + KUNIT_EXPECT_EQ(test, link_adjust.auth_delay, 2); + KUNIT_EXPECT_EQ(test, link_adjust.retry_limit, MAX_NUM_OF_ATTEMPTS); + KUNIT_EXPECT_EQ(test, hdcp1_disable, 0); + KUNIT_EXPECT_EQ(test, force_type, + MOD_HDCP_FORCE_TYPE_0); + KUNIT_EXPECT_FALSE(test, link_adjust.hdcp2.use_fw_locality_check); + KUNIT_EXPECT_TRUE(test, link_adjust.hdcp2.use_sw_locality_fallback); +} + +/** + * dm_test_hdcp_get_adjustments_type1_policy - TYPE1 disables HDCP1 and forces TYPE1 + * @test: KUnit test context + * + * When encryption is enabled with content TYPE1, hdcp1 should be + * disabled, force_type should be TYPE_1, and fw_locality_check should + * be enabled when hdcp_lc_force_fw_enable is set. + */ +static void dm_test_hdcp_get_adjustments_type1_policy(struct kunit *test) +{ + struct mod_hdcp_link_adjustment link_adjust; + struct mod_hdcp_display_adjustment display_adjust; + unsigned int disable; + unsigned int hdcp1_disable; + unsigned int force_type; + + hdcp_get_link_display_adjustments(true, DRM_MODE_HDCP_CONTENT_TYPE1, + false, true, false, &link_adjust, &display_adjust); + disable = display_adjust.disable; + hdcp1_disable = link_adjust.hdcp1.disable; + force_type = link_adjust.hdcp2.force_type; + + KUNIT_EXPECT_EQ(test, disable, + MOD_HDCP_DISPLAY_NOT_DISABLE); + KUNIT_EXPECT_EQ(test, link_adjust.auth_delay, 2); + KUNIT_EXPECT_EQ(test, link_adjust.retry_limit, MAX_NUM_OF_ATTEMPTS); + KUNIT_EXPECT_EQ(test, hdcp1_disable, 1); + KUNIT_EXPECT_EQ(test, force_type, + MOD_HDCP_FORCE_TYPE_1); + KUNIT_EXPECT_TRUE(test, link_adjust.hdcp2.use_fw_locality_check); + KUNIT_EXPECT_FALSE(test, link_adjust.hdcp2.use_sw_locality_fallback); +} + +/** + * dm_test_hdcp_get_adjustments_fused_io_enables_fw_check - fused_io enables FW locality check + * @test: KUnit test context + * + * When fused_io_supported is true, use_fw_locality_check should be + * enabled regardless of hdcp_lc_force_fw_enable. + */ +static void dm_test_hdcp_get_adjustments_fused_io_enables_fw_check(struct kunit *test) +{ + struct mod_hdcp_link_adjustment link_adjust; + struct mod_hdcp_display_adjustment display_adjust; + + hdcp_get_link_display_adjustments(true, DRM_MODE_HDCP_CONTENT_TYPE0, + true, false, false, &link_adjust, &display_adjust); + + KUNIT_EXPECT_TRUE(test, link_adjust.hdcp2.use_fw_locality_check); +} + /* Tests for process_output() */ -/* - * Helper: allocate and initialise a minimal hdcp_workqueue sufficient for - * process_output() testing. Only the three delayed works accessed by +/** + * alloc_test_workqueue - allocate a minimal hdcp_workqueue for testing + * @test: KUnit test context for managed allocation + * + * Allocates and initialises a minimal hdcp_workqueue sufficient for + * process_output() testing. Only the three delayed works accessed by * process_output() are initialised; everything else is zeroed. */ static struct hdcp_workqueue *alloc_test_workqueue(struct kunit *test) @@ -33,9 +263,12 @@ static struct hdcp_workqueue *alloc_test_workqueue(struct kunit *test) return work; } -/* +/** + * dm_test_process_output_property_validate_always_scheduled - validate_dwork always queued + * @test: KUnit test context + * * process_output() always schedules property_validate_dwork with delay=0, - * which queues the work item directly (bypassing the timer). Use + * which queues the work item directly (bypassing the timer). Uses * work_pending() rather than delayed_work_pending() to detect this. */ static void dm_test_process_output_property_validate_always_scheduled(struct kunit *test) @@ -52,8 +285,12 @@ static void dm_test_process_output_property_validate_always_scheduled(struct kun cancel_delayed_work_sync(&work->property_validate_dwork); } -/* - * output.callback_needed=true must schedule callback_dwork. +/** + * dm_test_process_output_callback_needed - callback_needed schedules callback_dwork + * @test: KUnit test context + * + * When output.callback_needed is true, process_output() must schedule + * callback_dwork with the specified delay. */ static void dm_test_process_output_callback_needed(struct kunit *test) { @@ -70,8 +307,12 @@ static void dm_test_process_output_callback_needed(struct kunit *test) cancel_delayed_work_sync(&work->property_validate_dwork); } -/* - * output.callback_stop=true must cancel a previously scheduled callback_dwork. +/** + * dm_test_process_output_callback_stop - callback_stop cancels callback_dwork + * @test: KUnit test context + * + * When output.callback_stop is true, process_output() must cancel a + * previously scheduled callback_dwork. */ static void dm_test_process_output_callback_stop(struct kunit *test) { @@ -90,8 +331,12 @@ static void dm_test_process_output_callback_stop(struct kunit *test) cancel_delayed_work_sync(&work->property_validate_dwork); } -/* - * output.watchdog_timer_needed=true must schedule watchdog_timer_dwork. +/** + * dm_test_process_output_watchdog_needed - watchdog_needed schedules watchdog_dwork + * @test: KUnit test context + * + * When output.watchdog_timer_needed is true, process_output() must + * schedule watchdog_timer_dwork with the specified delay. */ static void dm_test_process_output_watchdog_needed(struct kunit *test) { @@ -108,9 +353,12 @@ static void dm_test_process_output_watchdog_needed(struct kunit *test) cancel_delayed_work_sync(&work->property_validate_dwork); } -/* - * output.watchdog_timer_stop=true must cancel a previously scheduled - * watchdog_timer_dwork. +/** + * dm_test_process_output_watchdog_stop - watchdog_stop cancels watchdog_dwork + * @test: KUnit test context + * + * When output.watchdog_timer_stop is true, process_output() must cancel + * a previously scheduled watchdog_timer_dwork. */ static void dm_test_process_output_watchdog_stop(struct kunit *test) { @@ -129,9 +377,12 @@ static void dm_test_process_output_watchdog_stop(struct kunit *test) cancel_delayed_work_sync(&work->property_validate_dwork); } -/* - * Both callback_needed and watchdog_timer_needed set: both dworks are - * scheduled independently. +/** + * dm_test_process_output_callback_and_watchdog_needed - both dworks scheduled independently + * @test: KUnit test context + * + * When both callback_needed and watchdog_timer_needed are set, + * process_output() must schedule both dworks independently. */ static void dm_test_process_output_callback_and_watchdog_needed(struct kunit *test) { @@ -154,6 +405,18 @@ static void dm_test_process_output_callback_and_watchdog_needed(struct kunit *te /* End of tests for process_output() */ static struct kunit_case dm_hdcp_test_cases[] = { + /* hdcp_get_content_protection_from_status() */ + KUNIT_CASE(dm_test_hdcp_get_cp_disabled_returns_desired), + KUNIT_CASE(dm_test_hdcp_get_cp_type0_returns_enabled), + KUNIT_CASE(dm_test_hdcp_get_cp_type1_returns_enabled), + KUNIT_CASE(dm_test_hdcp_get_cp_type1_rejects_type0_status), + KUNIT_CASE(dm_test_hdcp_get_cp_type0_rejects_type1_status), + /* hdcp_get_link_display_adjustments() */ + KUNIT_CASE(dm_test_hdcp_get_adjustments_disable_authentication), + KUNIT_CASE(dm_test_hdcp_get_adjustments_type0_policy), + KUNIT_CASE(dm_test_hdcp_get_adjustments_type1_policy), + KUNIT_CASE(dm_test_hdcp_get_adjustments_fused_io_enables_fw_check), + /* process_output() */ KUNIT_CASE(dm_test_process_output_property_validate_always_scheduled), KUNIT_CASE(dm_test_process_output_callback_needed), KUNIT_CASE(dm_test_process_output_callback_stop), diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c new file mode 100644 index 000000000000..33014a2d2222 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_helpers.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "dm_helpers.h" +#include "ddc_service_types.h" +#include "amdgpu_dm_helpers.h" +#include "amdgpu_dm_kunit_test_helpers.h" + +/* Tests for edid_extract_panel_id() */ + +/** + * dm_test_edid_extract_panel_id_basic - Test Edid extract panel id basic + * @test: The KUnit test context + */ +static void dm_test_edid_extract_panel_id_basic(struct kunit *test) +{ + struct edid *edid; + u32 panel_id; + + edid = kunit_kzalloc(test, sizeof(*edid), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, edid); + + edid->mfg_id[0] = 0x12; + edid->mfg_id[1] = 0x34; + edid->prod_code[0] = 0xAB; + edid->prod_code[1] = 0xCD; + + panel_id = edid_extract_panel_id(edid); + + /* + * Expected: (0x12 << 24) | (0x34 << 16) | EDID_PRODUCT_ID(edid) + * EDID_PRODUCT_ID = prod_code[0] | (prod_code[1] << 8) = 0xAB | 0xCD00 = 0xCDAB + * Result: 0x12340000 | 0x0000CDAB = 0x1234CDAB + */ + KUNIT_EXPECT_EQ(test, panel_id, (u32)0x1234CDAB); +} + +/** + * dm_test_edid_extract_panel_id_zeros - Test Edid extract panel id zeros + * @test: The KUnit test context + */ +static void dm_test_edid_extract_panel_id_zeros(struct kunit *test) +{ + struct edid *edid; + + edid = kunit_kzalloc(test, sizeof(*edid), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, edid); + + KUNIT_EXPECT_EQ(test, edid_extract_panel_id(edid), 0U); +} + +/* Tests for dm_is_freesync_pcon_whitelist() */ + +/** + * dm_test_freesync_pcon_whitelist_all_known - Test all known Freesync Pcon whitelist entries + * @test: The KUnit test context + * + * Iterates over the driver's whitelist table directly so that any ID added + * to dm_freesync_pcon_whitelist[] is automatically covered by this test. + */ +static void dm_test_freesync_pcon_whitelist_all_known(struct kunit *test) +{ + u32 i; + + for (i = 0; i < dm_freesync_pcon_whitelist_count(); i++) + KUNIT_EXPECT_TRUE(test, + dm_is_freesync_pcon_whitelist(dm_freesync_pcon_whitelist[i])); +} + +/** + * dm_test_freesync_pcon_whitelist_not_in_list - Test Freesync pcon whitelist not in list + * @test: The KUnit test context + */ +static void dm_test_freesync_pcon_whitelist_not_in_list(struct kunit *test) +{ + /* 0xFFFFFF is not a known whitelist device */ + KUNIT_EXPECT_FALSE(test, dm_is_freesync_pcon_whitelist(0xFFFFFF)); +} + +/** + * dm_test_freesync_pcon_whitelist_zero - Test Freesync pcon whitelist zero + * @test: The KUnit test context + */ +static void dm_test_freesync_pcon_whitelist_zero(struct kunit *test) +{ + KUNIT_EXPECT_FALSE(test, dm_is_freesync_pcon_whitelist(0)); +} + +/* Tests for populate_hdmi_info_from_connector() */ + +/** + * dm_test_populate_hdmi_scdc_present_true - Test Populate hdmi scdc present true + * @test: The KUnit test context + */ +static void dm_test_populate_hdmi_scdc_present_true(struct kunit *test) +{ + struct drm_hdmi_info *hdmi; + struct dc_edid_caps *caps; + + hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, hdmi); + caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, caps); + + hdmi->scdc.supported = true; + + populate_hdmi_info_from_connector(true, hdmi, caps); + + KUNIT_EXPECT_TRUE(test, caps->scdc_present); +} + +/** + * dm_test_populate_hdmi_scdc_present_false - Test Populate hdmi scdc present false + * @test: The KUnit test context + */ +static void dm_test_populate_hdmi_scdc_present_false(struct kunit *test) +{ + struct drm_hdmi_info *hdmi; + struct dc_edid_caps *caps; + + hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, hdmi); + caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, caps); + + hdmi->scdc.supported = false; + caps->scdc_present = true; /* pre-set to confirm it gets cleared */ + + populate_hdmi_info_from_connector(true, hdmi, caps); + + KUNIT_EXPECT_FALSE(test, caps->scdc_present); +} + +/** + * dm_test_populate_hdmi_frl_dsc_10bpc - Test HDMI FRL DSC 10 bpc caps + * @test: The KUnit test context + */ +static void dm_test_populate_hdmi_frl_dsc_10bpc(struct kunit *test) +{ + struct drm_hdmi_info *hdmi; + struct dc_edid_caps *caps; + + hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, hdmi); + caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, caps); + + hdmi->max_lanes = 4; + hdmi->max_frl_rate_per_lane = 12; + hdmi->dsc_cap.v_1p2 = true; + hdmi->dsc_cap.bpc_supported = 10; + hdmi->dsc_cap.all_bpp = true; + hdmi->dsc_cap.native_420 = true; + hdmi->dsc_cap.max_slices = 8; + hdmi->dsc_cap.clk_per_slice = 400; + hdmi->dsc_cap.max_lanes = 4; + hdmi->dsc_cap.max_frl_rate_per_lane = 10; + hdmi->dsc_cap.total_chunk_kbytes = 7; + + populate_hdmi_info_from_connector(true, hdmi, caps); + + KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 6); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_10bpc); + KUNIT_EXPECT_FALSE(test, caps->frl_dsc_12bpc); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_all_bpp); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_native_420); + KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 5); + KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 5); + KUNIT_EXPECT_EQ(test, caps->frl_dsc_total_chunk_kbytes, 7); +} + +/** + * dm_test_populate_hdmi_frl_dsc_12bpc - Test HDMI FRL DSC 12 bpc caps + * @test: The KUnit test context + */ +static void dm_test_populate_hdmi_frl_dsc_12bpc(struct kunit *test) +{ + struct drm_hdmi_info *hdmi; + struct dc_edid_caps *caps; + + hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, hdmi); + caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, caps); + + hdmi->max_lanes = 3; + hdmi->max_frl_rate_per_lane = 6; + hdmi->dsc_cap.v_1p2 = true; + hdmi->dsc_cap.bpc_supported = 12; + hdmi->dsc_cap.max_slices = 16; + hdmi->dsc_cap.clk_per_slice = 400; + hdmi->dsc_cap.max_lanes = 3; + hdmi->dsc_cap.max_frl_rate_per_lane = 3; + + populate_hdmi_info_from_connector(true, hdmi, caps); + + KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 2); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support); + KUNIT_EXPECT_FALSE(test, caps->frl_dsc_10bpc); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_12bpc); + KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 7); + KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 1); +} + +/** + * dm_test_populate_hdmi_frl_dsc_unknown_values - Test HDMI FRL DSC unknown values + * @test: The KUnit test context + */ +static void dm_test_populate_hdmi_frl_dsc_unknown_values(struct kunit *test) +{ + struct drm_hdmi_info *hdmi; + struct dc_edid_caps *caps; + + hdmi = kunit_kzalloc(test, sizeof(*hdmi), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, hdmi); + caps = kunit_kzalloc(test, sizeof(*caps), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, caps); + + hdmi->max_lanes = 2; + hdmi->max_frl_rate_per_lane = 3; + hdmi->dsc_cap.v_1p2 = true; + hdmi->dsc_cap.bpc_supported = 8; + hdmi->dsc_cap.max_slices = 3; + hdmi->dsc_cap.clk_per_slice = 340; + hdmi->dsc_cap.max_lanes = 2; + hdmi->dsc_cap.max_frl_rate_per_lane = 12; + + populate_hdmi_info_from_connector(true, hdmi, caps); + + KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 0); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support); + KUNIT_EXPECT_FALSE(test, caps->frl_dsc_10bpc); + KUNIT_EXPECT_FALSE(test, caps->frl_dsc_12bpc); + KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 0); + KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 0); +} + +/* Tests for dm_get_adaptive_sync_support_type() */ + +/** + * dm_test_adaptive_sync_type_none_default - Test Adaptive sync type none default + * @test: The KUnit test context + */ +static void dm_test_adaptive_sync_type_none_default(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* dongle_type = 0 (DISPLAY_DONGLE_NONE) → default case → TYPE_NONE */ + KUNIT_EXPECT_EQ(test, + (int)dm_get_adaptive_sync_support_type(link), + (int)ADAPTIVE_SYNC_TYPE_NONE); +} + +/** + * dm_test_adaptive_sync_type_converter_no_conditions - Converter without caps + * @test: The KUnit test context + */ +static void dm_test_adaptive_sync_type_converter_no_conditions(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* HDMI converter but no adaptive sync cap → still NONE */ + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER; + + KUNIT_EXPECT_EQ(test, + (int)dm_get_adaptive_sync_support_type(link), + (int)ADAPTIVE_SYNC_TYPE_NONE); +} + +/** + * dm_test_adaptive_sync_type_converter_partial_conditions - Partial caps + * @test: The KUnit test context + */ +static void dm_test_adaptive_sync_type_converter_partial_conditions(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* Cap set and whitelist ID, but allow_invalid_MSA_timing_param = false */ + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER; + link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 1; + link->dpcd_caps.allow_invalid_MSA_timing_param = false; + link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_0060AD; + + KUNIT_EXPECT_EQ(test, + (int)dm_get_adaptive_sync_support_type(link), + (int)ADAPTIVE_SYNC_TYPE_NONE); +} + +/** + * dm_test_adaptive_sync_type_pcon_whitelist - Test Adaptive sync type pcon whitelist + * @test: The KUnit test context + */ +static void dm_test_adaptive_sync_type_pcon_whitelist(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* All conditions met → FREESYNC_TYPE_PCON_IN_WHITELIST */ + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER; + link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 1; + link->dpcd_caps.allow_invalid_MSA_timing_param = true; + link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_0060AD; + + KUNIT_EXPECT_EQ(test, + (int)dm_get_adaptive_sync_support_type(link), + (int)FREESYNC_TYPE_PCON_IN_WHITELIST); +} + +/** + * dm_test_adaptive_sync_type_converter_nonwhitelist - Converter not whitelisted + * @test: The KUnit test context + */ +static void dm_test_adaptive_sync_type_converter_nonwhitelist(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* All conditions met but branch_dev_id not in whitelist → NONE */ + link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_HDMI_CONVERTER; + link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 1; + link->dpcd_caps.allow_invalid_MSA_timing_param = true; + link->dpcd_caps.branch_dev_id = 0xFFFFFF; + + KUNIT_EXPECT_EQ(test, + (int)dm_get_adaptive_sync_support_type(link), + (int)ADAPTIVE_SYNC_TYPE_NONE); +} + +/* Tests for dm_helpers_is_fullscreen() and dm_helpers_is_hdr_on() */ + +/** + * dm_test_helpers_is_fullscreen_returns_false - Test Helpers is fullscreen returns false + * @test: The KUnit test context + */ +static void dm_test_helpers_is_fullscreen_returns_false(struct kunit *test) +{ + /* Stub — always returns false */ + KUNIT_EXPECT_FALSE(test, dm_helpers_is_fullscreen(NULL, NULL)); +} + +/** + * dm_test_helpers_is_hdr_on_returns_false - Test Helpers is hdr on returns false + * @test: The KUnit test context + */ +static void dm_test_helpers_is_hdr_on_returns_false(struct kunit *test) +{ + /* Stub — always returns false */ + KUNIT_EXPECT_FALSE(test, dm_helpers_is_hdr_on(NULL, NULL)); +} + +/* Tests for get_max_frl_rate() */ + +/** + * dm_test_get_max_frl_rate_3lanes_3gbps - Test Get max frl rate 3lanes 3gbps + * @test: The KUnit test context + */ +static void dm_test_get_max_frl_rate_3lanes_3gbps(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, get_max_frl_rate(3, 3), 1); +} + +/** + * dm_test_get_max_frl_rate_3lanes_6gbps - Test Get max frl rate 3lanes 6gbps + * @test: The KUnit test context + */ +static void dm_test_get_max_frl_rate_3lanes_6gbps(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, get_max_frl_rate(3, 6), 2); +} + +/** + * dm_test_get_max_frl_rate_4lanes_6gbps - Test Get max frl rate 4lanes 6gbps + * @test: The KUnit test context + */ +static void dm_test_get_max_frl_rate_4lanes_6gbps(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 6), 3); +} + +/** + * dm_test_get_max_frl_rate_4lanes_8gbps - Test Get max frl rate 4lanes 8gbps + * @test: The KUnit test context + */ +static void dm_test_get_max_frl_rate_4lanes_8gbps(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 8), 4); +} + +/** + * dm_test_get_max_frl_rate_4lanes_10gbps - Test Get max frl rate 4lanes 10gbps + * @test: The KUnit test context + */ +static void dm_test_get_max_frl_rate_4lanes_10gbps(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 10), 5); +} + +/** + * dm_test_get_max_frl_rate_4lanes_12gbps - Test Get max frl rate 4lanes 12gbps + * @test: The KUnit test context + */ +static void dm_test_get_max_frl_rate_4lanes_12gbps(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, get_max_frl_rate(4, 12), 6); +} + +/** + * dm_test_get_max_frl_rate_unknown - Test Get max frl rate unknown + * @test: The KUnit test context + */ +static void dm_test_get_max_frl_rate_unknown(struct kunit *test) +{ + /* Unknown lane/rate combination → 0 */ + KUNIT_EXPECT_EQ(test, get_max_frl_rate(2, 3), 0); +} + +/* Tests for dm_dtn_log_begin() / dm_dtn_log_append_v() / dm_dtn_log_end() */ + +/** + * dm_test_dtn_log_buffer_accumulates - Test DTN log buffer accumulation + * @test: The KUnit test context + */ +static void dm_test_dtn_log_buffer_accumulates(struct kunit *test) +{ + struct dc_log_buffer_ctx log_ctx = {0}; + + dm_dtn_log_begin(NULL, &log_ctx); + dm_dtn_log_append_v(NULL, &log_ctx, "x=%d\n", 7); + dm_dtn_log_end(NULL, &log_ctx); + + KUNIT_ASSERT_NOT_NULL(test, log_ctx.buf); + KUNIT_EXPECT_STREQ(test, log_ctx.buf, "[dtn begin]\nx=7\n[dtn end]\n"); + KUNIT_EXPECT_EQ(test, log_ctx.pos, strlen("[dtn begin]\nx=7\n[dtn end]\n")); + + kvfree(log_ctx.buf); +} + +/** + * dm_test_dtn_log_null_ctx_no_crash - Test DTN log helpers with NULL log buffer + * @test: The KUnit test context + */ +static void dm_test_dtn_log_null_ctx_no_crash(struct kunit *test) +{ + /* NULL log_ctx redirects to dmesg and must not dereference a buffer */ + dm_dtn_log_begin(NULL, NULL); + dm_dtn_log_append_v(NULL, NULL, "value %d\n", 1); + dm_dtn_log_end(NULL, NULL); + + KUNIT_EXPECT_TRUE(test, true); +} + +/* Tests for dm_helpers_dp_read_dpcd() / dm_helpers_dp_write_dpcd() */ + +/** + * dm_test_dp_read_dpcd_null_priv - Test DPCD read returns false without connector + * @test: The KUnit test context + */ +static void dm_test_dp_read_dpcd_null_priv(struct kunit *test) +{ + struct dc_link *link; + uint8_t data = 0; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* link->priv (aconnector) is NULL → early return false */ + KUNIT_EXPECT_FALSE(test, + dm_helpers_dp_read_dpcd(NULL, link, 0, &data, sizeof(data))); +} + +/** + * dm_test_dp_write_dpcd_null_priv - Test DPCD write returns false without connector + * @test: The KUnit test context + */ +static void dm_test_dp_write_dpcd_null_priv(struct kunit *test) +{ + struct dc_link *link; + uint8_t data = 0; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + /* link->priv (aconnector) is NULL → early return false */ + KUNIT_EXPECT_FALSE(test, + dm_helpers_dp_write_dpcd(NULL, link, 0, &data, sizeof(data))); +} + +/* Tests for dm_helpers_dp_mst_start_top_mgr() / dm_helpers_dp_mst_stop_top_mgr() */ + +/** + * dm_test_mst_start_top_mgr_null_priv - Test MST start returns false without connector + * @test: The KUnit test context + */ +static void dm_test_mst_start_top_mgr_null_priv(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + KUNIT_EXPECT_FALSE(test, dm_helpers_dp_mst_start_top_mgr(NULL, link, false)); +} + +/** + * dm_test_mst_stop_top_mgr_null_priv - Test MST stop returns false without connector + * @test: The KUnit test context + */ +static void dm_test_mst_stop_top_mgr_null_priv(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + KUNIT_EXPECT_FALSE(test, dm_helpers_dp_mst_stop_top_mgr(NULL, link)); +} + +/** + * dm_test_mst_start_top_mgr_boot - Test MST start boot path on a connector-backed link + * @test: The KUnit test context + * + * Uses the DRM KUnit mock device to back the connector so the link is a + * realistic connector-backed link. The boot path short-circuits and returns + * true without touching the MST topology manager. + */ +static void dm_test_mst_start_top_mgr_boot(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct amdgpu_device *adev; + struct dc_link *link; + + adev = dm_kunit_alloc_adev(test); + + link = dm_kunit_alloc_link(test); + + aconnector = dm_kunit_alloc_connector(test, adev, NULL); + + link->priv = aconnector; + + KUNIT_EXPECT_TRUE(test, dm_helpers_dp_mst_start_top_mgr(NULL, link, true)); +} + +/* Tests for dm_helpers_dp_write_hblank_reduction() */ + +/** + * dm_test_dp_write_hblank_reduction_false - Test hblank reduction stub returns false + * @test: The KUnit test context + */ +static void dm_test_dp_write_hblank_reduction_false(struct kunit *test) +{ + KUNIT_EXPECT_FALSE(test, dm_helpers_dp_write_hblank_reduction(NULL, NULL)); +} + +static struct kunit_case amdgpu_dm_helpers_test_cases[] = { + /* edid_extract_panel_id */ + KUNIT_CASE(dm_test_edid_extract_panel_id_basic), + KUNIT_CASE(dm_test_edid_extract_panel_id_zeros), + /* dm_is_freesync_pcon_whitelist */ + KUNIT_CASE(dm_test_freesync_pcon_whitelist_all_known), + KUNIT_CASE(dm_test_freesync_pcon_whitelist_not_in_list), + KUNIT_CASE(dm_test_freesync_pcon_whitelist_zero), + /* populate_hdmi_info_from_connector */ + KUNIT_CASE(dm_test_populate_hdmi_scdc_present_true), + KUNIT_CASE(dm_test_populate_hdmi_scdc_present_false), + KUNIT_CASE(dm_test_populate_hdmi_frl_dsc_10bpc), + KUNIT_CASE(dm_test_populate_hdmi_frl_dsc_12bpc), + KUNIT_CASE(dm_test_populate_hdmi_frl_dsc_unknown_values), + /* dm_get_adaptive_sync_support_type */ + KUNIT_CASE(dm_test_adaptive_sync_type_none_default), + KUNIT_CASE(dm_test_adaptive_sync_type_converter_no_conditions), + KUNIT_CASE(dm_test_adaptive_sync_type_converter_partial_conditions), + KUNIT_CASE(dm_test_adaptive_sync_type_pcon_whitelist), + KUNIT_CASE(dm_test_adaptive_sync_type_converter_nonwhitelist), + /* dm_helpers_is_fullscreen / dm_helpers_is_hdr_on */ + KUNIT_CASE(dm_test_helpers_is_fullscreen_returns_false), + KUNIT_CASE(dm_test_helpers_is_hdr_on_returns_false), + /* get_max_frl_rate */ + KUNIT_CASE(dm_test_get_max_frl_rate_3lanes_3gbps), + KUNIT_CASE(dm_test_get_max_frl_rate_3lanes_6gbps), + KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_6gbps), + KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_8gbps), + KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_10gbps), + KUNIT_CASE(dm_test_get_max_frl_rate_4lanes_12gbps), + KUNIT_CASE(dm_test_get_max_frl_rate_unknown), + /* dm_dtn_log_begin / dm_dtn_log_append_v / dm_dtn_log_end */ + KUNIT_CASE(dm_test_dtn_log_buffer_accumulates), + KUNIT_CASE(dm_test_dtn_log_null_ctx_no_crash), + /* dm_helpers_dp_read_dpcd / dm_helpers_dp_write_dpcd */ + KUNIT_CASE(dm_test_dp_read_dpcd_null_priv), + KUNIT_CASE(dm_test_dp_write_dpcd_null_priv), + /* dm_helpers_dp_mst_start_top_mgr / dm_helpers_dp_mst_stop_top_mgr */ + KUNIT_CASE(dm_test_mst_start_top_mgr_null_priv), + KUNIT_CASE(dm_test_mst_stop_top_mgr_null_priv), + KUNIT_CASE(dm_test_mst_start_top_mgr_boot), + /* dm_helpers_dp_write_hblank_reduction */ + KUNIT_CASE(dm_test_dp_write_hblank_reduction_false), + {} +}; + +static struct kunit_suite amdgpu_dm_helpers_test_suite = { + .name = "amdgpu_dm_helpers", + .test_cases = amdgpu_dm_helpers_test_cases, +}; + +kunit_test_suite(amdgpu_dm_helpers_test_suite); + +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_helpers"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c new file mode 100644 index 000000000000..a73a6dd146d6 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_irq_test.c @@ -0,0 +1,909 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_irq.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_irq.h" +#include "amdgpu_dm_kunit_test_helpers.h" +#include "dmub/dmub_srv.h" + +static void dm_test_irq_handler(void *arg) +{ +} + +static void dm_test_irq_handler_alt(void *arg) +{ +} + +static void dm_test_crtc_list_del(void *data) +{ + struct amdgpu_crtc *acrtc = data; + + list_del_init(&acrtc->base.head); +} + +/* Tests for amdgpu_dm_hpd_to_dal_irq_source() */ + +/** + * dm_test_hpd_to_dal_irq_source_hpd1 - Test Hpd to dal irq source hpd1 + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_hpd1(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_1), + (int)DC_IRQ_SOURCE_HPD1); +} + +/** + * dm_test_hpd_to_dal_irq_source_hpd2 - Test Hpd to dal irq source hpd2 + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_hpd2(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_2), + (int)DC_IRQ_SOURCE_HPD2); +} + +/** + * dm_test_hpd_to_dal_irq_source_hpd3 - Test Hpd to dal irq source hpd3 + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_hpd3(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_3), + (int)DC_IRQ_SOURCE_HPD3); +} + +/** + * dm_test_hpd_to_dal_irq_source_hpd4 - Test Hpd to dal irq source hpd4 + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_hpd4(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_4), + (int)DC_IRQ_SOURCE_HPD4); +} + +/** + * dm_test_hpd_to_dal_irq_source_hpd5 - Test Hpd to dal irq source hpd5 + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_hpd5(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_5), + (int)DC_IRQ_SOURCE_HPD5); +} + +/** + * dm_test_hpd_to_dal_irq_source_hpd6 - Test Hpd to dal irq source hpd6 + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_hpd6(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_6), + (int)DC_IRQ_SOURCE_HPD6); +} + +/** + * dm_test_hpd_to_dal_irq_source_invalid - Test Hpd to dal irq source invalid + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_invalid(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(AMDGPU_HPD_NONE), + (int)DC_IRQ_SOURCE_INVALID); +} + +/** + * dm_test_hpd_to_dal_irq_source_out_of_range - Test Hpd to dal irq source out of range + * @test: The KUnit test context + */ +static void dm_test_hpd_to_dal_irq_source_out_of_range(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_hpd_to_dal_irq_source(99), + (int)DC_IRQ_SOURCE_INVALID); +} + +/* Tests for are_sinks_equal() */ + +/** + * dm_test_are_sinks_equal_both_null - Test Are sinks equal both null + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_both_null(struct kunit *test) +{ + KUNIT_EXPECT_FALSE(test, are_sinks_equal(NULL, NULL)); +} + +/** + * dm_test_are_sinks_equal_first_null - Test Are sinks equal first null + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_first_null(struct kunit *test) +{ + struct dc_sink *sink2; + + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + KUNIT_EXPECT_FALSE(test, are_sinks_equal(NULL, sink2)); +} + +/** + * dm_test_are_sinks_equal_second_null - Test Are sinks equal second null + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_second_null(struct kunit *test) +{ + struct dc_sink *sink1; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + + KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, NULL)); +} + +/** + * dm_test_are_sinks_equal_different_signal - Test Are sinks equal different signal + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_different_signal(struct kunit *test) +{ + struct dc_sink *sink1, *sink2; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; + + KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2)); +} + +/** + * dm_test_are_sinks_equal_different_edid_length - Test Are sinks equal different edid length + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_different_edid_length(struct kunit *test) +{ + struct dc_sink *sink1, *sink2; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink1->dc_edid.length = 128; + sink2->dc_edid.length = 256; + + KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2)); +} + +/** + * dm_test_are_sinks_equal_different_edid_data - Test Are sinks equal different edid data + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_different_edid_data(struct kunit *test) +{ + struct dc_sink *sink1, *sink2; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink1->dc_edid.length = 4; + sink2->dc_edid.length = 4; + memset(sink1->dc_edid.raw_edid, 0xAA, 4); + memset(sink2->dc_edid.raw_edid, 0xBB, 4); + + KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2)); +} + +/** + * dm_test_are_sinks_equal_identical - Test Are sinks equal identical + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_identical(struct kunit *test) +{ + struct dc_sink *sink1, *sink2; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink1->dc_edid.length = 4; + sink2->dc_edid.length = 4; + memset(sink1->dc_edid.raw_edid, 0xAA, 4); + memset(sink2->dc_edid.raw_edid, 0xAA, 4); + + KUNIT_EXPECT_TRUE(test, are_sinks_equal(sink1, sink2)); +} + +/** + * dm_test_are_sinks_equal_zero_length - Test Are sinks equal zero length + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_zero_length(struct kunit *test) +{ + struct dc_sink *sink1, *sink2; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + sink1->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; + sink2->sink_signal = SIGNAL_TYPE_DISPLAY_PORT; + sink1->dc_edid.length = 0; + sink2->dc_edid.length = 0; + + KUNIT_EXPECT_TRUE(test, are_sinks_equal(sink1, sink2)); +} + +/** + * dm_test_are_sinks_equal_full_edid_identical - Test Are sinks equal full edid identical + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_full_edid_identical(struct kunit *test) +{ + struct dc_sink *sink1, *sink2; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink1->dc_edid.length = 128; + sink2->dc_edid.length = 128; + memset(sink1->dc_edid.raw_edid, 0x5A, 128); + memset(sink2->dc_edid.raw_edid, 0x5A, 128); + + KUNIT_EXPECT_TRUE(test, are_sinks_equal(sink1, sink2)); +} + +/** + * dm_test_are_sinks_equal_full_edid_last_byte_differs - Test Are sinks equal last byte differs + * @test: The KUnit test context + */ +static void dm_test_are_sinks_equal_full_edid_last_byte_differs(struct kunit *test) +{ + struct dc_sink *sink1, *sink2; + + sink1 = kunit_kzalloc(test, sizeof(*sink1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink1); + sink2 = kunit_kzalloc(test, sizeof(*sink2), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sink2); + + sink1->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink2->sink_signal = SIGNAL_TYPE_HDMI_TYPE_A; + sink1->dc_edid.length = 128; + sink2->dc_edid.length = 128; + memset(sink1->dc_edid.raw_edid, 0x5A, 128); + memset(sink2->dc_edid.raw_edid, 0x5A, 128); + sink2->dc_edid.raw_edid[127] = 0x5B; + + KUNIT_EXPECT_FALSE(test, are_sinks_equal(sink1, sink2)); +} + +/* Tests for dmub_notification_type_str() */ + +/** + * dm_test_notification_str_no_data - Test Notification str no data + * @test: The KUnit test context + */ +static void dm_test_notification_str_no_data(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_NO_DATA), "NO_DATA"); +} + +/** + * dm_test_notification_str_aux_reply - Test Notification str aux reply + * @test: The KUnit test context + */ +static void dm_test_notification_str_aux_reply(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_AUX_REPLY), "AUX_REPLY"); +} + +/** + * dm_test_notification_str_hpd - Test Notification str hpd + * @test: The KUnit test context + */ +static void dm_test_notification_str_hpd(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_HPD), "HPD"); +} + +/** + * dm_test_notification_str_hpd_irq - Test Notification str hpd irq + * @test: The KUnit test context + */ +static void dm_test_notification_str_hpd_irq(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_HPD_IRQ), "HPD_IRQ"); +} + +/** + * dm_test_notification_str_set_config - Test Notification str set config + * @test: The KUnit test context + */ +static void dm_test_notification_str_set_config(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_SET_CONFIG_REPLY), + "SET_CONFIG_REPLY"); +} + +/** + * dm_test_notification_str_dpia - Test Notification str dpia + * @test: The KUnit test context + */ +static void dm_test_notification_str_dpia(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_DPIA_NOTIFICATION), + "DPIA_NOTIFICATION"); +} + +/** + * dm_test_notification_str_hpd_sense - Test Notification str hpd sense + * @test: The KUnit test context + */ +static void dm_test_notification_str_hpd_sense(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_HPD_SENSE_NOTIFY), + "HPD_SENSE_NOTIFY"); +} + +/** + * dm_test_notification_str_fused_io - Test Notification str fused io + * @test: The KUnit test context + */ +static void dm_test_notification_str_fused_io(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_FUSED_IO), + "FUSED_IO"); +} + +/** + * dm_test_notification_str_unknown - Test Notification str unknown + * @test: The KUnit test context + */ +static void dm_test_notification_str_unknown(struct kunit *test) +{ + KUNIT_EXPECT_STREQ(test, dmub_notification_type_str(DMUB_NOTIFICATION_MAX), ""); +} + +/* Tests for amdgpu_dm_irq_init() */ + +/** + * dm_test_irq_init_initializes_lists - Test irq init initializes list heads + * @test: The KUnit test context + */ +static void dm_test_irq_init_initializes_lists(struct kunit *test) +{ + struct amdgpu_device *adev; + int src; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) { + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[src])); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[src])); + } +} + +/* Tests for amdgpu_dm_irq_register_interrupt() */ + +/** + * dm_test_irq_register_rejects_null_params - Test register rejects null params + * @test: The KUnit test context + */ +static void dm_test_irq_register_rejects_null_params(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_HPD1; + + KUNIT_EXPECT_NULL(test, + amdgpu_dm_irq_register_interrupt(adev, NULL, + dm_test_irq_handler, NULL)); + KUNIT_EXPECT_NULL(test, + amdgpu_dm_irq_register_interrupt(adev, &int_params, NULL, NULL)); +} + +/** + * dm_test_irq_register_rejects_invalid_context - Test register rejects context + * @test: The KUnit test context + */ +static void dm_test_irq_register_rejects_invalid_context(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + int_params.int_context = INTERRUPT_CONTEXT_NUMBER; + int_params.irq_source = DC_IRQ_SOURCE_HPD1; + + KUNIT_EXPECT_NULL(test, + amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, NULL)); +} + +/** + * dm_test_irq_register_rejects_invalid_source - Test register rejects source + * @test: The KUnit test context + */ +static void dm_test_irq_register_rejects_invalid_source(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_INVALID; + + KUNIT_EXPECT_NULL(test, + amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, NULL)); +} + +/** + * dm_test_irq_register_adds_low_context_handler - Test register adds low handler + * @test: The KUnit test context + */ +static void dm_test_irq_register_adds_low_context_handler(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + void *handler; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_HPD1; + + handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); + KUNIT_EXPECT_FALSE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD1])); + + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, + dm_test_irq_handler); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); +} + +/** + * dm_test_irq_register_adds_high_context_handler - Test register adds high handler + * @test: The KUnit test context + */ +static void dm_test_irq_register_adds_high_context_handler(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + void *handler; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_HPD2; + + handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); + KUNIT_EXPECT_FALSE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD2])); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD2])); + + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD2, + dm_test_irq_handler); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD2])); +} + +/** + * dm_test_irq_register_multiple_handlers - Test register keeps multiple handlers + * @test: The KUnit test context + */ +static void dm_test_irq_register_multiple_handlers(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + struct list_head *hnd_list; + void *handler1, *handler2; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_HPD1; + + handler1 = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler1); + handler2 = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler_alt, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler2); + + hnd_list = &adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1]; + KUNIT_EXPECT_EQ(test, list_count_nodes(hnd_list), 2); + + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, + dm_test_irq_handler); + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, + dm_test_irq_handler_alt); + KUNIT_EXPECT_TRUE(test, list_empty(hnd_list)); +} + +/** + * dm_test_irq_register_separate_contexts - Test register same source in two contexts + * @test: The KUnit test context + */ +static void dm_test_irq_register_separate_contexts(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + void *handler; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + int_params.irq_source = DC_IRQ_SOURCE_HPD5; + + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); + + KUNIT_EXPECT_FALSE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD5])); + KUNIT_EXPECT_FALSE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD5])); + + /* + * A single unregister call stops at the first context where the handler + * is found (low context), leaving the high context handler in place. + */ + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD5, + dm_test_irq_handler); + + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD5])); + KUNIT_EXPECT_FALSE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD5])); + + /* A second call removes the remaining high context handler. */ + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD5, + dm_test_irq_handler); + + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD5])); +} + +/* Tests for amdgpu_dm_irq_unregister_interrupt() */ + +/** + * dm_test_irq_unregister_rejects_invalid_source - Test unregister rejects source + * @test: The KUnit test context + */ +static void dm_test_irq_unregister_rejects_invalid_source(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_INVALID, + dm_test_irq_handler); + + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD1])); +} + +/** + * dm_test_irq_unregister_rejects_null_handler - Test unregister rejects handler + * @test: The KUnit test context + */ +static void dm_test_irq_unregister_rejects_null_handler(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, + DAL_INVALID_IRQ_HANDLER_IDX); + + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD1])); +} + +/** + * dm_test_irq_unregister_handler_not_found - Test unregister keeps unmatched handler + * @test: The KUnit test context + */ +static void dm_test_irq_unregister_handler_not_found(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + void *handler; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_HPD1; + handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); + + /* Unregister a handler that was never registered for this source. */ + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, + dm_test_irq_handler_alt); + + /* The originally registered handler must still be present. */ + KUNIT_EXPECT_FALSE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); + + amdgpu_dm_irq_unregister_interrupt(adev, DC_IRQ_SOURCE_HPD1, + dm_test_irq_handler); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD1])); +} + +/* Tests for amdgpu_dm_irq_fini() */ + +/** + * dm_test_irq_fini_removes_registered_handlers - Test fini removes handlers + * @test: The KUnit test context + */ +static void dm_test_irq_fini_removes_registered_handlers(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_interrupt_params int_params = { 0 }; + void *handler; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_HPD3; + handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); + + int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT; + int_params.irq_source = DC_IRQ_SOURCE_HPD4; + handler = amdgpu_dm_irq_register_interrupt(adev, &int_params, + dm_test_irq_handler, adev); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, handler); + + amdgpu_dm_irq_fini(adev); + + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[DC_IRQ_SOURCE_HPD3])); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[DC_IRQ_SOURCE_HPD4])); +} + +/** + * dm_test_irq_fini_on_empty_tables - Test fini on tables with no handlers + * @test: The KUnit test context + */ +static void dm_test_irq_fini_on_empty_tables(struct kunit *test) +{ + struct amdgpu_device *adev; + int src; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, adev); + KUNIT_ASSERT_EQ(test, amdgpu_dm_irq_init(adev), 0); + + amdgpu_dm_irq_fini(adev); + + for (src = 0; src < DAL_IRQ_SOURCES_NUMBER; src++) { + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_low_tab[src])); + KUNIT_EXPECT_TRUE(test, + list_empty(&adev->dm.irq_handler_list_high_tab[src])); + } +} + +/* Tests for amdgpu_dm_get_crtc_by_otg_inst() */ + +/** + * dm_test_get_crtc_by_otg_inst_returns_match - Test CRTC lookup by OTG instance + * @test: The KUnit test context + */ +static void dm_test_get_crtc_by_otg_inst_returns_match(struct kunit *test) +{ + struct amdgpu_crtc *acrtc_a, *acrtc_b; + struct amdgpu_device *adev; + struct drm_device *drm; + + adev = dm_kunit_alloc_adev(test); + drm = &adev->ddev; + + acrtc_a = kunit_kzalloc(test, sizeof(*acrtc_a), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_a); + acrtc_b = kunit_kzalloc(test, sizeof(*acrtc_b), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc_b); + + INIT_LIST_HEAD(&acrtc_a->base.head); + INIT_LIST_HEAD(&acrtc_b->base.head); + acrtc_a->otg_inst = 1; + acrtc_b->otg_inst = 3; + + list_add_tail(&acrtc_a->base.head, &drm->mode_config.crtc_list); + KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_crtc_list_del, + acrtc_a), 0); + list_add_tail(&acrtc_b->base.head, &drm->mode_config.crtc_list); + KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_crtc_list_del, + acrtc_b), 0); + + KUNIT_EXPECT_PTR_EQ(test, amdgpu_dm_get_crtc_by_otg_inst(adev, 3), acrtc_b); +} + +/** + * dm_test_get_crtc_by_otg_inst_returns_null - Test CRTC lookup misses unknown OTG + * @test: The KUnit test context + */ +static void dm_test_get_crtc_by_otg_inst_returns_null(struct kunit *test) +{ + struct amdgpu_crtc *acrtc; + struct amdgpu_device *adev; + struct drm_device *drm; + + adev = dm_kunit_alloc_adev(test); + drm = &adev->ddev; + + acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, acrtc); + + INIT_LIST_HEAD(&acrtc->base.head); + acrtc->otg_inst = 2; + + list_add_tail(&acrtc->base.head, &drm->mode_config.crtc_list); + KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_crtc_list_del, + acrtc), 0); + + KUNIT_EXPECT_NULL(test, amdgpu_dm_get_crtc_by_otg_inst(adev, 5)); +} + +/** + * dm_test_get_crtc_by_otg_inst_empty_list - Test CRTC lookup on empty CRTC list + * @test: The KUnit test context + */ +static void dm_test_get_crtc_by_otg_inst_empty_list(struct kunit *test) +{ + struct amdgpu_device *adev; + + adev = dm_kunit_alloc_adev(test); + + KUNIT_EXPECT_NULL(test, amdgpu_dm_get_crtc_by_otg_inst(adev, 0)); +} + +static struct kunit_case amdgpu_dm_irq_tests[] = { + /* amdgpu_dm_hpd_to_dal_irq_source */ + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd1), + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd2), + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd3), + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd4), + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd5), + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_hpd6), + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_invalid), + KUNIT_CASE(dm_test_hpd_to_dal_irq_source_out_of_range), + /* are_sinks_equal */ + KUNIT_CASE(dm_test_are_sinks_equal_both_null), + KUNIT_CASE(dm_test_are_sinks_equal_first_null), + KUNIT_CASE(dm_test_are_sinks_equal_second_null), + KUNIT_CASE(dm_test_are_sinks_equal_different_signal), + KUNIT_CASE(dm_test_are_sinks_equal_different_edid_length), + KUNIT_CASE(dm_test_are_sinks_equal_different_edid_data), + KUNIT_CASE(dm_test_are_sinks_equal_identical), + KUNIT_CASE(dm_test_are_sinks_equal_zero_length), + KUNIT_CASE(dm_test_are_sinks_equal_full_edid_identical), + KUNIT_CASE(dm_test_are_sinks_equal_full_edid_last_byte_differs), + /* dmub_notification_type_str */ + KUNIT_CASE(dm_test_notification_str_no_data), + KUNIT_CASE(dm_test_notification_str_aux_reply), + KUNIT_CASE(dm_test_notification_str_hpd), + KUNIT_CASE(dm_test_notification_str_hpd_irq), + KUNIT_CASE(dm_test_notification_str_set_config), + KUNIT_CASE(dm_test_notification_str_dpia), + KUNIT_CASE(dm_test_notification_str_hpd_sense), + KUNIT_CASE(dm_test_notification_str_fused_io), + KUNIT_CASE(dm_test_notification_str_unknown), + /* amdgpu_dm_irq_init */ + KUNIT_CASE(dm_test_irq_init_initializes_lists), + /* amdgpu_dm_irq_register_interrupt */ + KUNIT_CASE(dm_test_irq_register_rejects_null_params), + KUNIT_CASE(dm_test_irq_register_rejects_invalid_context), + KUNIT_CASE(dm_test_irq_register_rejects_invalid_source), + KUNIT_CASE(dm_test_irq_register_adds_low_context_handler), + KUNIT_CASE(dm_test_irq_register_adds_high_context_handler), + KUNIT_CASE(dm_test_irq_register_multiple_handlers), + KUNIT_CASE(dm_test_irq_register_separate_contexts), + /* amdgpu_dm_irq_unregister_interrupt */ + KUNIT_CASE(dm_test_irq_unregister_rejects_invalid_source), + KUNIT_CASE(dm_test_irq_unregister_rejects_null_handler), + KUNIT_CASE(dm_test_irq_unregister_handler_not_found), + /* amdgpu_dm_irq_fini */ + KUNIT_CASE(dm_test_irq_fini_removes_registered_handlers), + KUNIT_CASE(dm_test_irq_fini_on_empty_tables), + /* amdgpu_dm_get_crtc_by_otg_inst */ + KUNIT_CASE(dm_test_get_crtc_by_otg_inst_returns_match), + KUNIT_CASE(dm_test_get_crtc_by_otg_inst_returns_null), + KUNIT_CASE(dm_test_get_crtc_by_otg_inst_empty_list), + {} +}; + +static struct kunit_suite amdgpu_dm_irq_test_suite = { + .name = "amdgpu_dm_irq", + .test_cases = amdgpu_dm_irq_tests, +}; + +kunit_test_suite(amdgpu_dm_irq_test_suite); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_irq"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c index f3b3f77aafd5..7dfb3b351d20 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_ism_test.c @@ -9,20 +9,7 @@ #include "dc.h" #include "amdgpu_dm_ism.h" - -/* - * Helper: allocate and zero-initialise a dc_stream_state for timing tests. - * Only the timing sub-struct is accessed by the functions under test. - */ -static struct dc_stream_state *alloc_test_stream(struct kunit *test) -{ - struct dc_stream_state *stream; - - stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, stream); - - return stream; -} +#include "amdgpu_dm_kunit_test_helpers.h" /* * Helper: allocate and zero-initialise an ISM instance. @@ -275,7 +262,7 @@ static void dm_test_ism_sso_delay_null_stream(struct kunit *test) static void dm_test_ism_sso_delay_zero_frames(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); stream->timing.v_total = 1125; stream->timing.h_total = 2200; @@ -288,7 +275,7 @@ static void dm_test_ism_sso_delay_zero_frames(struct kunit *test) static void dm_test_ism_sso_delay_1080p60_3frames(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t expected_one_frame_ns, expected; /* @@ -311,7 +298,7 @@ static void dm_test_ism_sso_delay_1080p60_3frames(struct kunit *test) static void dm_test_ism_sso_delay_4k60_1frame(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t expected_one_frame_ns; /* @@ -347,7 +334,7 @@ static void dm_test_ism_idle_delay_null_stream(struct kunit *test) static void dm_test_ism_idle_delay_zero_filter_frames(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); stream->timing.v_total = 1125; stream->timing.h_total = 2200; @@ -361,7 +348,7 @@ static void dm_test_ism_idle_delay_zero_filter_frames(struct kunit *test) static void dm_test_ism_idle_delay_zero_entry_count(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); stream->timing.v_total = 1125; stream->timing.h_total = 2200; @@ -376,7 +363,7 @@ static void dm_test_ism_idle_delay_zero_entry_count(struct kunit *test) static void dm_test_ism_idle_delay_zero_delay_frames(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); stream->timing.v_total = 1125; stream->timing.h_total = 2200; @@ -392,7 +379,7 @@ static void dm_test_ism_idle_delay_zero_delay_frames(struct kunit *test) static void dm_test_ism_idle_delay_no_short_idles(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t one_frame_ns; /* @@ -426,7 +413,7 @@ static void dm_test_ism_idle_delay_no_short_idles(struct kunit *test) static void dm_test_ism_idle_delay_enough_short_idles(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t one_frame_ns, expected; /* @@ -461,7 +448,7 @@ static void dm_test_ism_idle_delay_enough_short_idles(struct kunit *test) static void dm_test_ism_idle_delay_wraps_around_buffer(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t one_frame_ns, expected; /* @@ -497,7 +484,7 @@ static void dm_test_ism_idle_delay_wraps_around_buffer(struct kunit *test) static void dm_test_ism_idle_delay_old_history_cutoff(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t one_frame_ns; /* @@ -545,7 +532,7 @@ static void dm_test_ism_idle_delay_old_history_cutoff(struct kunit *test) static void dm_test_ism_idle_delay_mixed_durations(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t one_frame_ns; /* @@ -586,7 +573,7 @@ static void dm_test_ism_idle_delay_mixed_durations(struct kunit *test) static void dm_test_ism_idle_delay_entry_count_exceeds_history_size(struct kunit *test) { struct amdgpu_dm_ism *ism = alloc_test_ism(test); - struct dc_stream_state *stream = alloc_test_stream(test); + struct dc_stream_state *stream = dm_kunit_alloc_stream(test, NULL); uint64_t one_frame_ns, expected; /* diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c new file mode 100644 index 000000000000..58615cdbe854 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_helpers.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit test helpers for amdgpu_dm tests. + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "dc.h" +#include "core_types.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_kunit_test_helpers.h" + +struct amdgpu_device *dm_kunit_alloc_adev(struct kunit *test) +{ + struct drm_device *drm; + struct device *dev; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(struct amdgpu_device), + offsetof(struct amdgpu_device, ddev), + DRIVER_MODESET | DRIVER_ATOMIC); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + return drm_to_adev(drm); +} +EXPORT_SYMBOL(dm_kunit_alloc_adev); + +struct dc_link *dm_kunit_alloc_link(struct kunit *test) +{ + struct dc_link *link; + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + return link; +} +EXPORT_SYMBOL(dm_kunit_alloc_link); + +struct dc_link *dm_kunit_alloc_link_with_ctx(struct kunit *test) +{ + struct dc_link *link; + struct dc_context *ctx; + struct dc *dc; + + link = dm_kunit_alloc_link(test); + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dc); + + link->ctx = ctx; + ctx->dc = dc; + dc->ctx = ctx; + + return link; +} +EXPORT_SYMBOL(dm_kunit_alloc_link_with_ctx); + +struct amdgpu_display_manager *dm_kunit_alloc_dm(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + struct dc *dc; + struct dc_state *state; + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm); + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dc); + + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, state); + + dm->dc = dc; + dc->current_state = state; + + return dm; +} +EXPORT_SYMBOL(dm_kunit_alloc_dm); + +struct dc_stream_state *dm_kunit_alloc_stream(struct kunit *test, + struct dc_link *link) +{ + struct dc_stream_state *stream; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + stream->link = link; + kref_init(&stream->refcount); + + return stream; +} +EXPORT_SYMBOL(dm_kunit_alloc_stream); + +void dm_kunit_add_stream_to_state(struct kunit *test, struct dc_state *state, + unsigned int index, struct dc_link *link) +{ + struct dc_stream_state *stream; + + KUNIT_ASSERT_LT(test, index, (unsigned int)MAX_PIPES); + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stream); + + stream->link = link; + state->streams[index] = stream; + if (state->stream_count <= index) + state->stream_count = index + 1; +} +EXPORT_SYMBOL(dm_kunit_add_stream_to_state); + +struct amdgpu_dm_connector *dm_kunit_alloc_connector(struct kunit *test, + struct amdgpu_device *adev, + struct dc_link *link) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + if (adev) + aconnector->base.dev = &adev->ddev; + aconnector->dc_link = link; + + return aconnector; +} +EXPORT_SYMBOL(dm_kunit_alloc_connector); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("KUnit test helpers for amdgpu_dm tests"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_test_helpers.h b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_test_helpers.h new file mode 100644 index 000000000000..0f1c48fa2128 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_kunit_test_helpers.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* + * KUnit test helpers for amdgpu_dm tests. + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#ifndef AMDGPU_DM_KUNIT_TEST_HELPERS_H +#define AMDGPU_DM_KUNIT_TEST_HELPERS_H + +#include + +struct amdgpu_device; +struct amdgpu_display_manager; +struct amdgpu_dm_connector; +struct dc_link; +struct dc_state; +struct dc_stream_state; + +struct amdgpu_device *dm_kunit_alloc_adev(struct kunit *test); +struct dc_link *dm_kunit_alloc_link(struct kunit *test); +struct dc_link *dm_kunit_alloc_link_with_ctx(struct kunit *test); +struct amdgpu_display_manager *dm_kunit_alloc_dm(struct kunit *test); +struct dc_stream_state *dm_kunit_alloc_stream(struct kunit *test, + struct dc_link *link); +void dm_kunit_add_stream_to_state(struct kunit *test, struct dc_state *state, + unsigned int index, struct dc_link *link); +struct amdgpu_dm_connector *dm_kunit_alloc_connector(struct kunit *test, + struct amdgpu_device *adev, + struct dc_link *link); + +#endif /* AMDGPU_DM_KUNIT_TEST_HELPERS_H */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c new file mode 100644 index 000000000000..3a663ee0ca2b --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_mst_types_test.c @@ -0,0 +1,1092 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_mst_types.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include + +#include +#include +#include +#include +#include + +#include "dc.h" +#include "dpcd_defs.h" +#include "dmub_cmd.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_mst_types.h" +#include "amdgpu_dm_kunit_test_helpers.h" +#include "inc/link_service.h" + +/* + * Minimal mock DPCD backing store and AUX transfer callback used to exercise + * the DPCD read paths without real hardware. + */ +static u8 dm_mst_test_dpcd[0x10]; +static u8 dm_mst_test_desc_dpcd[0x10]; +static struct aux_payload dm_mst_test_last_payload; +static int dm_mst_test_aux_transfer_raw_result; +static enum aux_return_code_type dm_mst_test_aux_transfer_raw_operation_result; + +static int dm_mst_test_aux_transfer_raw(struct ddc_service *ddc, + struct aux_payload *payload, + enum aux_return_code_type *operation_result) +{ + size_t i; + + dm_mst_test_last_payload = *payload; + *operation_result = dm_mst_test_aux_transfer_raw_operation_result; + + if (dm_mst_test_aux_transfer_raw_result) + return dm_mst_test_aux_transfer_raw_result; + + if (payload->write) + return 0; + + for (i = 0; i < payload->length; i++) + payload->data[i] = dm_mst_test_dpcd[(payload->address + i) & 0xf]; + + return payload->length; +} + +static void dm_mst_test_setup_dm_aux(struct amdgpu_dm_dp_aux *dm_aux, + struct ddc_service *ddc, + struct dc_link *link, + struct dc *dc, + struct link_service *link_srv, + struct dc_context *ctx, + struct amdgpu_device *adev) +{ + memset(&dm_mst_test_last_payload, 0, sizeof(dm_mst_test_last_payload)); + dm_mst_test_aux_transfer_raw_result = 0; + dm_mst_test_aux_transfer_raw_operation_result = AUX_RET_SUCCESS; + link_srv->aux_transfer_raw = dm_mst_test_aux_transfer_raw; + dc->link_srv = link_srv; + link->dc = dc; + ctx->driver_context = adev; + ddc->link = link; + ddc->ctx = ctx; + dm_aux->ddc_service = ddc; + dm_aux->aux.name = "dm_mst_test_dm_aux"; + dm_aux->aux.transfer = dm_dp_aux_transfer; + drm_dp_aux_init(&dm_aux->aux); + drm_dp_dpcd_set_probe(&dm_aux->aux, false); +} + +static const struct dc_link_status *dm_mst_test_get_status(const struct dc_link *link) +{ + return &link->link_status; +} + +static ssize_t dm_mst_test_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + size_t i; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_READ: + for (i = 0; i < msg->size; i++) + ((u8 *)msg->buffer)[i] = + dm_mst_test_dpcd[(msg->address + i) & 0xf]; + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + return msg->size; + case DP_AUX_NATIVE_WRITE: + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + return msg->size; + default: + return -EINVAL; + } +} + +static ssize_t dm_mst_test_desc_aux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + size_t i; + + if ((msg->request & ~DP_AUX_I2C_MOT) != DP_AUX_NATIVE_READ) + return -EINVAL; + + for (i = 0; i < msg->size; i++) + ((u8 *)msg->buffer)[i] = dm_mst_test_desc_dpcd[msg->address + i - DP_BRANCH_OUI]; + + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + return msg->size; +} + +/* Tests for needs_dsc_aux_workaround */ + +/** + * dm_mst_test_needs_dsc_aux_workaround_match - Test workaround triggers for matching device + * @test: KUnit test context + * + * Verify that needs_dsc_aux_workaround() returns true when the link has + * the specific branch device ID, DPCD rev 1.4, and sink count >= 2. + */ +static void dm_mst_test_needs_dsc_aux_workaround_match(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; + link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; + link->dpcd_caps.sink_count.bits.SINK_COUNT = 2; + + KUNIT_EXPECT_TRUE(test, needs_dsc_aux_workaround(link)); +} + +/** + * dm_mst_test_needs_dsc_aux_workaround_rev12 - Test workaround triggers for DPCD rev 1.2 + * @test: KUnit test context + * + * Verify that needs_dsc_aux_workaround() returns true when the link has + * the specific branch device ID, DPCD rev 1.2, and sink count >= 2. + */ +static void dm_mst_test_needs_dsc_aux_workaround_rev12(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; + link->dpcd_caps.dpcd_rev.raw = DPCD_REV_12; + link->dpcd_caps.sink_count.bits.SINK_COUNT = 3; + + KUNIT_EXPECT_TRUE(test, needs_dsc_aux_workaround(link)); +} + +/** + * dm_mst_test_needs_dsc_aux_workaround_wrong_dev_id - Test workaround skipped for wrong device + * @test: KUnit test context + * + * Verify that needs_dsc_aux_workaround() returns false when the branch + * device ID does not match DP_BRANCH_DEVICE_ID_90CC24. + */ +static void dm_mst_test_needs_dsc_aux_workaround_wrong_dev_id(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.branch_dev_id = 0x123456; + link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; + link->dpcd_caps.sink_count.bits.SINK_COUNT = 2; + + KUNIT_EXPECT_FALSE(test, needs_dsc_aux_workaround(link)); +} + +/** + * dm_mst_test_needs_dsc_aux_workaround_wrong_rev - Test workaround skipped for unsupported rev + * @test: KUnit test context + * + * Verify that needs_dsc_aux_workaround() returns false when the DPCD + * revision is neither 1.2 nor 1.4. + */ +static void dm_mst_test_needs_dsc_aux_workaround_wrong_rev(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; + link->dpcd_caps.dpcd_rev.raw = 0x11; /* DPCD 1.1 */ + link->dpcd_caps.sink_count.bits.SINK_COUNT = 2; + + KUNIT_EXPECT_FALSE(test, needs_dsc_aux_workaround(link)); +} + +/** + * dm_mst_test_needs_dsc_aux_workaround_low_sink_count - Test workaround skipped for single sink + * @test: KUnit test context + * + * Verify that needs_dsc_aux_workaround() returns false when the sink + * count is less than 2, even if device ID and DPCD rev match. + */ +static void dm_mst_test_needs_dsc_aux_workaround_low_sink_count(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; + link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; + link->dpcd_caps.sink_count.bits.SINK_COUNT = 1; + + KUNIT_EXPECT_FALSE(test, needs_dsc_aux_workaround(link)); +} + +/** + * dm_mst_test_needs_dsc_aux_workaround_zero_sink_count - Test workaround skipped for zero sinks + * @test: KUnit test context + * + * Verify that needs_dsc_aux_workaround() returns false when the sink + * count is zero, even if device ID and DPCD rev match. + */ +static void dm_mst_test_needs_dsc_aux_workaround_zero_sink_count(struct kunit *test) +{ + struct dc_link *link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, link); + + link->dpcd_caps.branch_dev_id = DP_BRANCH_DEVICE_ID_90CC24; + link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; + link->dpcd_caps.sink_count.bits.SINK_COUNT = 0; + + KUNIT_EXPECT_FALSE(test, needs_dsc_aux_workaround(link)); +} + +/* Tests for dm_mst_get_pbn_divider */ + +/** + * dm_mst_test_pbn_divider_null_link - Test pbn_divider with NULL link + * @test: KUnit test context + * + * Verify that dm_mst_get_pbn_divider() returns 0 when passed a NULL + * link pointer without crashing. + */ +static void dm_mst_test_pbn_divider_null_link(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, dm_mst_get_pbn_divider(NULL), 0U); +} + +/* Tests for amdgpu_dm_mst_reset_mst_connector_setting */ + +/** + * dm_mst_test_reset_connector_setting - Test MST connector setting reset + * @test: KUnit test context + * + * Verify that amdgpu_dm_mst_reset_mst_connector_setting() clears the cached + * EDID, DSC AUX, passthrough AUX, local bandwidth, and VC PBN state. + */ +static void dm_mst_test_reset_connector_setting(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_dp_mst_port *port; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, port); + + aconnector->drm_edid = (const struct drm_edid *)test; + aconnector->dsc_aux = (struct drm_dp_aux *)test; + aconnector->mst_output_port = port; + aconnector->mst_output_port->passthrough_aux = (struct drm_dp_aux *)test; + aconnector->mst_local_bw = 12345; + aconnector->vc_full_pbn = 678; + + amdgpu_dm_mst_reset_mst_connector_setting(aconnector); + + KUNIT_EXPECT_TRUE(test, aconnector->drm_edid == NULL); + KUNIT_EXPECT_TRUE(test, aconnector->dsc_aux == NULL); + KUNIT_EXPECT_TRUE(test, aconnector->mst_output_port->passthrough_aux == NULL); + KUNIT_EXPECT_EQ(test, aconnector->mst_local_bw, 0U); + KUNIT_EXPECT_EQ(test, aconnector->vc_full_pbn, 0U); +} + +/* Tests for retrieve_downstream_port_device */ + +/** + * dm_mst_test_retrieve_downstream_no_aux - Test retrieval bails out without AUX + * @test: KUnit test context + * + * Verify that retrieve_downstream_port_device() returns false when the + * connector has no DSC AUX channel and therefore cannot read DPCD. + */ +static void dm_mst_test_retrieve_downstream_no_aux(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + aconnector->dsc_aux = NULL; + + KUNIT_EXPECT_FALSE(test, retrieve_downstream_port_device(aconnector)); +} + +/** + * dm_mst_test_retrieve_downstream_present - Test retrieval parses DPCD 0x05 + * @test: KUnit test context + * + * Verify that retrieve_downstream_port_device() reads DP_DOWNSTREAMPORT_PRESENT + * over a mock AUX channel and caches the parsed downstream port fields. + */ +static void dm_mst_test_retrieve_downstream_present(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_dp_aux *aux; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + aux = kunit_kzalloc(test, sizeof(*aux), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, aux); + + memset(dm_mst_test_dpcd, 0, sizeof(dm_mst_test_dpcd)); + /* PORT_PRESENT = 1, PORT_TYPE = 2 (0b101) */ + dm_mst_test_dpcd[DP_DOWNSTREAMPORT_PRESENT] = 0x05; + + aux->name = "dm_mst_test_aux"; + aux->transfer = dm_mst_test_aux_transfer; + drm_dp_aux_init(aux); + drm_dp_dpcd_set_probe(aux, false); + aconnector->dsc_aux = aux; + + KUNIT_EXPECT_TRUE(test, retrieve_downstream_port_device(aconnector)); + KUNIT_EXPECT_EQ(test, + (int)aconnector->mst_downstream_port_present.fields.PORT_PRESENT, 1); + KUNIT_EXPECT_EQ(test, + (int)aconnector->mst_downstream_port_present.fields.PORT_TYPE, 2); +} + +/* Tests for retrieve_branch_specific_data */ + +/** + * dm_mst_test_retrieve_branch_no_parent - Test branch lookup needs a parent port + * @test: KUnit test context + * + * Verify that retrieve_branch_specific_data() returns false when the MST + * output port has no parent branch device to query. + */ +static void dm_mst_test_retrieve_branch_no_parent(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_dp_mst_port *port; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, port); + + port->parent = NULL; + aconnector->mst_output_port = port; + + KUNIT_EXPECT_FALSE(test, retrieve_branch_specific_data(aconnector)); +} + +/** + * dm_mst_test_retrieve_branch_reads_oui - Test branch OUI parsing + * @test: KUnit test context + * + * Verify that retrieve_branch_specific_data() reads the immediate upstream + * branch descriptor and caches its IEEE OUI value on the connector. + */ +static void dm_mst_test_retrieve_branch_reads_oui(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_branch *branch; + struct drm_dp_mst_port *port; + struct drm_dp_aux *aux; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + mgr = kunit_kzalloc(test, sizeof(*mgr), GFP_KERNEL); + branch = kunit_kzalloc(test, sizeof(*branch), GFP_KERNEL); + port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL); + aux = kunit_kzalloc(test, sizeof(*aux), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, mgr); + KUNIT_ASSERT_NOT_NULL(test, branch); + KUNIT_ASSERT_NOT_NULL(test, port); + KUNIT_ASSERT_NOT_NULL(test, aux); + + memset(dm_mst_test_desc_dpcd, 0, sizeof(dm_mst_test_desc_dpcd)); + dm_mst_test_desc_dpcd[0] = 0x12; + dm_mst_test_desc_dpcd[1] = 0x34; + dm_mst_test_desc_dpcd[2] = 0x56; + + aux->name = "dm_mst_test_desc_aux"; + aux->transfer = dm_mst_test_desc_aux_transfer; + drm_dp_aux_init(aux); + drm_dp_dpcd_set_probe(aux, false); + mgr->aux = aux; + port->parent = branch; + port->mgr = mgr; + port->aux.drm_dev = NULL; + aconnector->mst_output_port = port; + + KUNIT_EXPECT_TRUE(test, retrieve_branch_specific_data(aconnector)); + KUNIT_EXPECT_EQ(test, aconnector->branch_ieee_oui, 0x123456U); +} + +/** + * dm_mst_test_aux_result_success - AUX_RET_SUCCESS preserves the input result. + * @test: KUnit test context. + * + * On success the original (negative) transfer result must be returned unchanged. + */ +static void dm_mst_test_aux_result_success(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-5, AUX_RET_SUCCESS), (ssize_t)-5); + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(3, AUX_RET_SUCCESS), (ssize_t)3); +} + +/** + * dm_mst_test_aux_result_eio - HPD/unknown/protocol errors map to -EIO. + * @test: KUnit test context. + * + * AUX_RET_ERROR_HPD_DISCON, AUX_RET_ERROR_UNKNOWN, + * AUX_RET_ERROR_INVALID_OPERATION and AUX_RET_ERROR_PROTOCOL_ERROR all map to -EIO. + */ +static void dm_mst_test_aux_result_eio(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_HPD_DISCON), + (ssize_t)-EIO); + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_UNKNOWN), + (ssize_t)-EIO); + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_INVALID_OPERATION), + (ssize_t)-EIO); + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_PROTOCOL_ERROR), + (ssize_t)-EIO); +} + +/** + * dm_mst_test_aux_result_ebusy - invalid reply / engine acquire map to -EBUSY. + * @test: KUnit test context. + * + * AUX_RET_ERROR_INVALID_REPLY and AUX_RET_ERROR_ENGINE_ACQUIRE map to -EBUSY. + */ +static void dm_mst_test_aux_result_ebusy(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_INVALID_REPLY), + (ssize_t)-EBUSY); + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_ENGINE_ACQUIRE), + (ssize_t)-EBUSY); +} + +/** + * dm_mst_test_aux_result_timeout - AUX_RET_ERROR_TIMEOUT maps to -ETIMEDOUT. + * @test: KUnit test context. + */ +static void dm_mst_test_aux_result_timeout(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, dm_dp_aux_transfer_result(-1, AUX_RET_ERROR_TIMEOUT), + (ssize_t)-ETIMEDOUT); +} + +/** + * dm_mst_test_aux_transfer_native_read - native AUX read through DM callback. + * @test: KUnit test context. + * + * The DM AUX transfer callback should build a read payload, call the DC link + * service, and return the number of bytes provided by the fake backend. + */ +static void dm_mst_test_aux_transfer_native_read(struct kunit *test) +{ + struct amdgpu_dm_dp_aux *dm_aux; + struct amdgpu_device *adev; + struct ddc_service *ddc; + struct dc_link *link; + struct dc *dc; + struct link_service *link_srv; + struct dc_context *ctx; + u8 buffer[3] = { 0 }; + ssize_t ret; + + dm_aux = kunit_kzalloc(test, sizeof(*dm_aux), GFP_KERNEL); + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm_aux); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + memset(dm_mst_test_dpcd, 0, sizeof(dm_mst_test_dpcd)); + dm_mst_test_dpcd[4] = 0xaa; + dm_mst_test_dpcd[5] = 0xbb; + dm_mst_test_dpcd[6] = 0xcc; + dm_mst_test_setup_dm_aux(dm_aux, ddc, link, dc, link_srv, ctx, adev); + + ret = drm_dp_dpcd_read(&dm_aux->aux, 4, buffer, sizeof(buffer)); + + KUNIT_EXPECT_EQ(test, ret, (ssize_t)sizeof(buffer)); + KUNIT_EXPECT_EQ(test, buffer[0], (u8)0xaa); + KUNIT_EXPECT_EQ(test, buffer[1], (u8)0xbb); + KUNIT_EXPECT_EQ(test, buffer[2], (u8)0xcc); + KUNIT_EXPECT_FALSE(test, dm_mst_test_last_payload.write); + KUNIT_EXPECT_FALSE(test, dm_mst_test_last_payload.i2c_over_aux); + KUNIT_EXPECT_EQ(test, dm_mst_test_last_payload.address, 4U); +} + +/** + * dm_mst_test_aux_transfer_native_write - native AUX write through DM callback. + * @test: KUnit test context. + * + * A successful write with an ACK reply should report the requested write size + * and pass a write payload into the fake DC link service. + */ +static void dm_mst_test_aux_transfer_native_write(struct kunit *test) +{ + struct amdgpu_dm_dp_aux *dm_aux; + struct amdgpu_device *adev; + struct ddc_service *ddc; + struct dc_link *link; + struct dc *dc; + struct link_service *link_srv; + struct dc_context *ctx; + u8 buffer[2] = { 0x11, 0x22 }; + ssize_t ret; + + dm_aux = kunit_kzalloc(test, sizeof(*dm_aux), GFP_KERNEL); + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm_aux); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + dm_mst_test_setup_dm_aux(dm_aux, ddc, link, dc, link_srv, ctx, adev); + + ret = drm_dp_dpcd_write(&dm_aux->aux, 7, buffer, sizeof(buffer)); + + KUNIT_EXPECT_EQ(test, ret, (ssize_t)sizeof(buffer)); + KUNIT_EXPECT_TRUE(test, dm_mst_test_last_payload.write); + KUNIT_EXPECT_FALSE(test, dm_mst_test_last_payload.i2c_over_aux); + KUNIT_EXPECT_EQ(test, dm_mst_test_last_payload.address, 7U); + KUNIT_EXPECT_EQ(test, dm_mst_test_last_payload.length, + (u32)sizeof(buffer)); +} + +/** + * dm_mst_test_aux_transfer_partial_write - partial write reports byte count. + * @test: KUnit test context. + * + * A positive write result from the DC link service should be interpreted as a + * partial write and replaced with the first payload byte. + */ +static void dm_mst_test_aux_transfer_partial_write(struct kunit *test) +{ + struct amdgpu_dm_dp_aux *dm_aux; + struct amdgpu_device *adev; + struct ddc_service *ddc; + struct dc_link *link; + struct dc *dc; + struct link_service *link_srv; + struct dc_context *ctx; + u8 buffer[2] = { 1, 0xaa }; + struct drm_dp_aux_msg msg = { + .address = 7, + .request = DP_AUX_NATIVE_WRITE, + .buffer = buffer, + .size = sizeof(buffer), + }; + ssize_t ret; + + dm_aux = kunit_kzalloc(test, sizeof(*dm_aux), GFP_KERNEL); + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm_aux); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + dm_mst_test_setup_dm_aux(dm_aux, ddc, link, dc, link_srv, ctx, adev); + dm_mst_test_aux_transfer_raw_result = 1; + + ret = dm_dp_aux_transfer(&dm_aux->aux, &msg); + + KUNIT_EXPECT_EQ(test, ret, (ssize_t)buffer[0]); + KUNIT_EXPECT_TRUE(test, dm_mst_test_last_payload.write); + KUNIT_EXPECT_EQ(test, dm_mst_test_last_payload.address, 7U); +} + +/** + * dm_mst_test_aux_transfer_error_result - transfer errors are remapped. + * @test: KUnit test context. + * + * A negative DC link service result should be converted through + * dm_dp_aux_transfer_result() using the returned AUX operation result. + */ +static void dm_mst_test_aux_transfer_error_result(struct kunit *test) +{ + struct amdgpu_dm_dp_aux *dm_aux; + struct amdgpu_device *adev; + struct ddc_service *ddc; + struct dc_link *link; + struct dc *dc; + struct link_service *link_srv; + struct dc_context *ctx; + u8 buffer[2] = { 0 }; + ssize_t ret; + + dm_aux = kunit_kzalloc(test, sizeof(*dm_aux), GFP_KERNEL); + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm_aux); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + dm_mst_test_setup_dm_aux(dm_aux, ddc, link, dc, link_srv, ctx, adev); + dm_mst_test_aux_transfer_raw_result = -EIO; + dm_mst_test_aux_transfer_raw_operation_result = AUX_RET_ERROR_TIMEOUT; + + ret = drm_dp_dpcd_read(&dm_aux->aux, 4, buffer, sizeof(buffer)); + + KUNIT_EXPECT_EQ(test, ret, (ssize_t)-ETIMEDOUT); + KUNIT_EXPECT_FALSE(test, dm_mst_test_last_payload.write); + KUNIT_EXPECT_EQ(test, dm_mst_test_last_payload.address, 4U); +} + +/** + * dm_mst_test_aux_transfer_hpd_discon_quirk - HPD disconnect quirk succeeds. + * @test: KUnit test context. + * + * AUX_RET_ERROR_HPD_DISCON on the sideband down request address should be + * treated as a successful transfer when the platform quirk is enabled. + */ +static void dm_mst_test_aux_transfer_hpd_discon_quirk(struct kunit *test) +{ + struct amdgpu_dm_dp_aux *dm_aux; + struct amdgpu_device *adev; + struct ddc_service *ddc; + struct dc_link *link; + struct dc *dc; + struct link_service *link_srv; + struct dc_context *ctx; + u8 buffer[2] = { 2, 0 }; + ssize_t ret; + + dm_aux = kunit_kzalloc(test, sizeof(*dm_aux), GFP_KERNEL); + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + ddc = kunit_kzalloc(test, sizeof(*ddc), GFP_KERNEL); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm_aux); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ddc); + KUNIT_ASSERT_NOT_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + dm_mst_test_setup_dm_aux(dm_aux, ddc, link, dc, link_srv, ctx, adev); + adev->dm.aux_hpd_discon_quirk = true; + dm_mst_test_aux_transfer_raw_result = -EIO; + dm_mst_test_aux_transfer_raw_operation_result = AUX_RET_ERROR_HPD_DISCON; + + ret = drm_dp_dpcd_write(&dm_aux->aux, DP_SIDEBAND_MSG_DOWN_REQ_BASE, + buffer, sizeof(buffer)); + + KUNIT_EXPECT_EQ(test, ret, (ssize_t)sizeof(buffer)); + KUNIT_EXPECT_TRUE(test, dm_mst_test_last_payload.write); + KUNIT_EXPECT_EQ(test, dm_mst_test_last_payload.address, + DP_SIDEBAND_MSG_DOWN_REQ_BASE); +} + +/** + * dm_mst_test_fill_payload_flags_native_write - native write request decode. + * @test: KUnit test context. + * + * DP_AUX_NATIVE_WRITE clears i2c_over_aux and sets write; no I2C bits set. + */ +static void dm_mst_test_fill_payload_flags_native_write(struct kunit *test) +{ + struct aux_payload payload = { 0 }; + + dm_dp_aux_fill_payload_flags(DP_AUX_NATIVE_WRITE, &payload); + + KUNIT_EXPECT_FALSE(test, payload.i2c_over_aux); + KUNIT_EXPECT_TRUE(test, payload.write); + KUNIT_EXPECT_FALSE(test, payload.mot); + KUNIT_EXPECT_FALSE(test, payload.write_status_update); +} + +/** + * dm_mst_test_fill_payload_flags_native_read - native read request decode. + * @test: KUnit test context. + * + * DP_AUX_NATIVE_READ keeps i2c_over_aux clear; the I2C_READ bit clears write. + */ +static void dm_mst_test_fill_payload_flags_native_read(struct kunit *test) +{ + struct aux_payload payload = { 0 }; + + dm_dp_aux_fill_payload_flags(DP_AUX_NATIVE_READ, &payload); + + KUNIT_EXPECT_FALSE(test, payload.i2c_over_aux); + KUNIT_EXPECT_FALSE(test, payload.write); + KUNIT_EXPECT_FALSE(test, payload.mot); +} + +/** + * dm_mst_test_fill_payload_flags_i2c_read_mot - I2C read with MOT request decode. + * @test: KUnit test context. + * + * DP_AUX_I2C_READ sets i2c_over_aux and clears write; DP_AUX_I2C_MOT sets mot. + */ +static void dm_mst_test_fill_payload_flags_i2c_read_mot(struct kunit *test) +{ + struct aux_payload payload = { 0 }; + + dm_dp_aux_fill_payload_flags(DP_AUX_I2C_READ | DP_AUX_I2C_MOT, &payload); + + KUNIT_EXPECT_TRUE(test, payload.i2c_over_aux); + KUNIT_EXPECT_FALSE(test, payload.write); + KUNIT_EXPECT_TRUE(test, payload.mot); +} + +/** + * dm_mst_test_fill_payload_flags_write_status - write status update decode. + * @test: KUnit test context. + * + * DP_AUX_I2C_WRITE_STATUS_UPDATE sets write_status_update. + */ +static void dm_mst_test_fill_payload_flags_write_status(struct kunit *test) +{ + struct aux_payload payload = { 0 }; + + dm_dp_aux_fill_payload_flags(DP_AUX_I2C_WRITE | DP_AUX_I2C_WRITE_STATUS_UPDATE, + &payload); + + KUNIT_EXPECT_TRUE(test, payload.i2c_over_aux); + KUNIT_EXPECT_TRUE(test, payload.write_status_update); +} + +/** + * dm_mst_test_msg_ready_mask - ESI mask selection per message-ready type. + * @test: KUnit test context. + * + * DOWN_REP and UP_REQ each select their single bit; other types select both. + */ +static void dm_mst_test_msg_ready_mask(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(DOWN_REP_MSG_RDY_EVENT), + (u8)DP_DOWN_REP_MSG_RDY); + KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(UP_REQ_MSG_RDY_EVENT), + (u8)DP_UP_REQ_MSG_RDY); + KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(DOWN_OR_UP_MSG_RDY_EVENT), + (u8)(DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY)); + KUNIT_EXPECT_EQ(test, dm_mst_msg_ready_mask(NONE_MSG_RDY_EVENT), + (u8)(DP_DOWN_REP_MSG_RDY | DP_UP_REQ_MSG_RDY)); +} + +/** + * dm_mst_test_select_esi_dpcd_legacy - pre-1.2 DPCD ESI address/length. + * @test: KUnit test context. + * + * For DPCD rev < 0x12 the legacy DP_SINK_COUNT address/length pair is selected. + */ +static void dm_mst_test_select_esi_dpcd_legacy(struct kunit *test) +{ + int dpcd_addr = -1; + u8 dpcd_bytes_to_read = 0; + + dm_mst_select_esi_dpcd(0x11, &dpcd_addr, &dpcd_bytes_to_read); + + KUNIT_EXPECT_EQ(test, dpcd_addr, DP_SINK_COUNT); + KUNIT_EXPECT_EQ(test, (int)dpcd_bytes_to_read, + (int)(DP_LANE0_1_STATUS - DP_SINK_COUNT)); +} + +/** + * dm_mst_test_select_esi_dpcd_esi - 1.2+ DPCD ESI address/length. + * @test: KUnit test context. + * + * For DPCD rev >= 0x12 the ESI DP_SINK_COUNT_ESI address/length pair is selected. + */ +static void dm_mst_test_select_esi_dpcd_esi(struct kunit *test) +{ + int dpcd_addr = -1; + u8 dpcd_bytes_to_read = 0; + + dm_mst_select_esi_dpcd(0x14, &dpcd_addr, &dpcd_bytes_to_read); + + KUNIT_EXPECT_EQ(test, dpcd_addr, DP_SINK_COUNT_ESI); + KUNIT_EXPECT_EQ(test, (int)dpcd_bytes_to_read, + (int)(DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI)); +} + +/** + * dm_mst_test_sideband_msg_ready_no_ready_bits - Test idle sideband event + * @test: KUnit test context + * + * Verify that dm_handle_mst_sideband_msg_ready_event() returns cleanly when + * the ESI read succeeds but no DOWN_REP/UP_REQ ready bits are set. + */ +static void dm_mst_test_sideband_msg_ready_no_ready_bits(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + struct link_service *link_srv; + struct dc_link *link; + struct dc *dc; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + link_srv = kunit_kzalloc(test, sizeof(*link_srv), GFP_KERNEL); + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, link_srv); + KUNIT_ASSERT_NOT_NULL(test, link); + KUNIT_ASSERT_NOT_NULL(test, dc); + + mutex_init(&aconnector->handle_mst_msg_ready); + link_srv->get_status = dm_mst_test_get_status; + dc->link_srv = link_srv; + link->dc = dc; + link->dpcd_caps.dpcd_rev.raw = DPCD_REV_14; + link->link_status.dpcd_caps = &link->dpcd_caps; + aconnector->dc_link = link; + aconnector->dm_dp_aux.aux.name = "dm_mst_test_sideband_aux"; + aconnector->dm_dp_aux.aux.transfer = dm_mst_test_aux_transfer; + drm_dp_aux_init(&aconnector->dm_dp_aux.aux); + drm_dp_dpcd_set_probe(&aconnector->dm_dp_aux.aux, false); + memset(dm_mst_test_dpcd, 0, sizeof(dm_mst_test_dpcd)); + + dm_handle_mst_sideband_msg_ready_event(&aconnector->mst_mgr, + DOWN_REP_MSG_RDY_EVENT); + + KUNIT_EXPECT_EQ(test, dm_mst_test_dpcd[1], (u8)0); +} + +/** + * dm_mst_test_atomic_best_encoder - Test MST encoder selection + * @test: KUnit test context + * + * Verify that dm_mst_atomic_best_encoder() selects the MST encoder indexed by + * the CRTC ID in the connector's new atomic state. This uses structural DRM + * mocks only; registering connector/CRTC objects is unnecessary for this helper. + */ +static void dm_mst_test_atomic_best_encoder(struct kunit *test) +{ + struct drm_connector_state connector_state = { 0 }; + struct drm_atomic_commit state = { 0 }; + struct amdgpu_dm_connector *aconnector; + struct amdgpu_device *adev; + struct amdgpu_crtc *acrtc; + unsigned int connector_index = 3; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + acrtc = kunit_kzalloc(test, sizeof(*acrtc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, acrtc); + + aconnector->base.dev = &adev->ddev; + aconnector->base.index = connector_index; + acrtc->crtc_id = 2; + connector_state.connector = &aconnector->base; + connector_state.crtc = &acrtc->base; + state.num_connector = connector_index + 1; + state.connectors = kunit_kzalloc(test, + sizeof(*state.connectors) * state.num_connector, + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, state.connectors); + state.connectors[connector_index].ptr = &aconnector->base; + state.connectors[connector_index].new_state = &connector_state; + + KUNIT_EXPECT_PTR_EQ(test, dm_mst_atomic_best_encoder(&aconnector->base, &state), + &adev->dm.mst_encoders[2].base); +} + +/** + * dm_mst_test_create_fake_mst_encoders - Test fake MST encoder setup + * @test: KUnit test context + * + * Verify that dm_dp_create_fake_mst_encoders() initializes the requested MST + * encoders as DPMST encoders with the CRTC mask derived from the device state. + */ +static void dm_mst_test_create_fake_mst_encoders(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_device *drm; + int i; + + adev = dm_kunit_alloc_adev(test); + drm = &adev->ddev; + adev->dm.display_indexes_num = 3; + adev->mode_info.num_crtc = 3; + + dm_dp_create_fake_mst_encoders(adev); + + for (i = 0; i < adev->dm.display_indexes_num; i++) { + struct drm_encoder *encoder = &adev->dm.mst_encoders[i].base; + + KUNIT_EXPECT_PTR_EQ(test, encoder->dev, drm); + KUNIT_EXPECT_EQ(test, encoder->encoder_type, DRM_MODE_ENCODER_DPMST); + KUNIT_EXPECT_EQ(test, encoder->possible_crtcs, 0x7U); + KUNIT_EXPECT_TRUE(test, encoder->helper_private != NULL); + } +} + +/** + * dm_mst_test_atomic_check_no_old_crtc - Test atomic check no-op path + * @test: KUnit test context + * + * Verify that dm_dp_mst_atomic_check() returns success when the MST port's old + * connector state has no CRTC, before MST topology state is required. + */ +static void dm_mst_test_atomic_check_no_old_crtc(struct kunit *test) +{ + struct drm_connector_state *old_conn_state; + struct drm_connector_state *new_conn_state; + struct drm_atomic_commit *state; + struct amdgpu_dm_connector *aconnector; + struct amdgpu_dm_connector *root; + struct drm_dp_mst_port *port; + unsigned int connector_index = 2; + + old_conn_state = kunit_kzalloc(test, sizeof(*old_conn_state), GFP_KERNEL); + new_conn_state = kunit_kzalloc(test, sizeof(*new_conn_state), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + root = kunit_kzalloc(test, sizeof(*root), GFP_KERNEL); + port = kunit_kzalloc(test, sizeof(*port), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, old_conn_state); + KUNIT_ASSERT_NOT_NULL(test, new_conn_state); + KUNIT_ASSERT_NOT_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + KUNIT_ASSERT_NOT_NULL(test, root); + KUNIT_ASSERT_NOT_NULL(test, port); + + aconnector->base.index = connector_index; + aconnector->mst_root = root; + aconnector->mst_output_port = port; + port->connector = &aconnector->base; + old_conn_state->connector = &aconnector->base; + new_conn_state->connector = &aconnector->base; + state->num_connector = connector_index + 1; + state->connectors = kunit_kzalloc(test, + sizeof(*state->connectors) * state->num_connector, + GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, state->connectors); + state->connectors[connector_index].ptr = &aconnector->base; + state->connectors[connector_index].old_state = old_conn_state; + state->connectors[connector_index].new_state = new_conn_state; + + KUNIT_EXPECT_EQ(test, dm_dp_mst_atomic_check(&aconnector->base, state), 0); +} + +/** + * dm_mst_test_detect_unregistered - Test detect skips unregistered connector + * @test: KUnit test context + * + * Verify that dm_dp_mst_detect() returns disconnected for an unregistered + * connector before calling into the MST topology helper. + */ +static void dm_mst_test_detect_unregistered(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + aconnector->base.registration_state = DRM_CONNECTOR_UNREGISTERED; + + KUNIT_EXPECT_EQ(test, + dm_dp_mst_detect(&aconnector->base, NULL, false), + (int)connector_status_disconnected); +} + +/** + * dm_mst_test_fp_guarded_public_stubs - Test FP-off public fallbacks + * @test: KUnit test context + * + * When CONFIG_DRM_AMD_DC_FP is disabled, the public DSC validation helper + * has no FP body and must return DC_OK without touching its arguments. + */ +static void dm_mst_test_fp_guarded_public_stubs(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, dm_dp_mst_is_port_support_mode(NULL, NULL), + (enum dc_status)DC_OK); +} + +static struct kunit_case dm_mst_types_test_cases[] = { + /* needs_dsc_aux_workaround tests */ + KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_match), + KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_rev12), + KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_wrong_dev_id), + KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_wrong_rev), + KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_low_sink_count), + KUNIT_CASE(dm_mst_test_needs_dsc_aux_workaround_zero_sink_count), + /* dm_mst_get_pbn_divider tests */ + KUNIT_CASE(dm_mst_test_pbn_divider_null_link), + /* amdgpu_dm_mst_reset_mst_connector_setting tests */ + KUNIT_CASE(dm_mst_test_reset_connector_setting), + /* retrieve_downstream_port_device tests */ + KUNIT_CASE(dm_mst_test_retrieve_downstream_no_aux), + KUNIT_CASE(dm_mst_test_retrieve_downstream_present), + /* retrieve_branch_specific_data tests */ + KUNIT_CASE(dm_mst_test_retrieve_branch_no_parent), + KUNIT_CASE(dm_mst_test_retrieve_branch_reads_oui), + /* dm_dp_aux_transfer_result tests */ + KUNIT_CASE(dm_mst_test_aux_result_success), + KUNIT_CASE(dm_mst_test_aux_result_eio), + KUNIT_CASE(dm_mst_test_aux_result_ebusy), + KUNIT_CASE(dm_mst_test_aux_result_timeout), + KUNIT_CASE(dm_mst_test_aux_transfer_native_read), + KUNIT_CASE(dm_mst_test_aux_transfer_native_write), + KUNIT_CASE(dm_mst_test_aux_transfer_partial_write), + KUNIT_CASE(dm_mst_test_aux_transfer_error_result), + KUNIT_CASE(dm_mst_test_aux_transfer_hpd_discon_quirk), + /* dm_dp_aux_fill_payload_flags tests */ + KUNIT_CASE(dm_mst_test_fill_payload_flags_native_write), + KUNIT_CASE(dm_mst_test_fill_payload_flags_native_read), + KUNIT_CASE(dm_mst_test_fill_payload_flags_i2c_read_mot), + KUNIT_CASE(dm_mst_test_fill_payload_flags_write_status), + /* dm_mst_msg_ready_mask tests */ + KUNIT_CASE(dm_mst_test_msg_ready_mask), + /* dm_mst_select_esi_dpcd tests */ + KUNIT_CASE(dm_mst_test_select_esi_dpcd_legacy), + KUNIT_CASE(dm_mst_test_select_esi_dpcd_esi), + /* dm_handle_mst_sideband_msg_ready_event tests */ + KUNIT_CASE(dm_mst_test_sideband_msg_ready_no_ready_bits), + /* dm_mst_atomic_best_encoder tests */ + KUNIT_CASE(dm_mst_test_atomic_best_encoder), + /* dm_dp_create_fake_mst_encoders tests */ + KUNIT_CASE(dm_mst_test_create_fake_mst_encoders), + /* dm_dp_mst_atomic_check tests */ + KUNIT_CASE(dm_mst_test_atomic_check_no_old_crtc), + /* dm_dp_mst_detect tests */ + KUNIT_CASE(dm_mst_test_detect_unregistered), + /* CONFIG_DRM_AMD_DC_FP disabled public paths */ + KUNIT_CASE(dm_mst_test_fp_guarded_public_stubs), + {} +}; + +static struct kunit_suite dm_mst_types_test_suite = { + .name = "amdgpu_dm_mst_types", + .test_cases = dm_mst_types_test_cases, +}; + +kunit_test_suite(dm_mst_types_test_suite); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_mst_types"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c new file mode 100644 index 000000000000..46c9af432e37 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_plane_test.c @@ -0,0 +1,1228 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_plane.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + + #include + #include + #include "link_enc_cfg.h" + #include "amdgpu_dm_plane.h" + #include + #include + + +struct dm_test_dcc_cap_ctx { + bool callback_ret; + bool capable; + bool output_independent_64b_blks; + bool called; + struct dc_dcc_surface_param captured_input; +}; + +static struct dm_test_dcc_cap_ctx *dm_test_dcc_ctx; + +static bool dm_test_get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output) +{ + if (!dm_test_dcc_ctx) + return false; + + dm_test_dcc_ctx->called = true; + dm_test_dcc_ctx->captured_input = *input; + output->capable = dm_test_dcc_ctx->capable; + output->grph.rgb.independent_64b_blks = dm_test_dcc_ctx->output_independent_64b_blks; + + return dm_test_dcc_ctx->callback_ret; +} + +static void dm_test_init_validate_dcc_inputs(struct amdgpu_device **adev, + struct dc **dc, + struct dc_tiling_info *tiling_info, + struct dc_plane_dcc_param *dcc, + struct dc_plane_address *address, + struct plane_size *plane_size, + struct kunit *test) +{ + *adev = kunit_kzalloc(test, sizeof(**adev), GFP_KERNEL); + *dc = kunit_kzalloc(test, sizeof(**dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, *adev); + KUNIT_ASSERT_NOT_NULL(test, *dc); + + (*adev)->dm.dc = *dc; + (*adev)->family = AMDGPU_FAMILY_NV; + + tiling_info->gfx9.swizzle = 9; + dcc->enable = 1; + dcc->independent_64b_blks = 1; + plane_size->surface_size.width = 1920; + plane_size->surface_size.height = 1080; + + (void)address; +} + + +/** + * dm_test_plane_is_video_format_known_video() - Verify known video formats. + * @test: KUnit test context. + * + * Verify if NV12, NV21, and P010 are treated as video formats. + */ +static void dm_test_plane_is_video_format_known_video(struct kunit *test) +{ + KUNIT_EXPECT_TRUE(test, amdgpu_dm_plane_is_video_format(DRM_FORMAT_NV12)); + KUNIT_EXPECT_TRUE(test, amdgpu_dm_plane_is_video_format(DRM_FORMAT_NV21)); + KUNIT_EXPECT_TRUE(test, amdgpu_dm_plane_is_video_format(DRM_FORMAT_P010)); +} + +/** + * dm_test_fill_blending_defaults() - Verify default blending output values. + * @test: KUnit test context. + * + * Verify if default blending output values are used for opaque alpha and no + * per-pixel blending. + */ +static void dm_test_fill_blending_defaults(struct kunit *test) +{ + struct drm_plane_state state = { 0 }; + bool per_pixel_alpha; + bool pre_multiplied_alpha; + bool global_alpha; + int global_alpha_value; + + state.pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE; + state.alpha = 0xffff; + + amdgpu_dm_plane_fill_blending_from_plane_state(&state, + &per_pixel_alpha, + &pre_multiplied_alpha, + &global_alpha, + &global_alpha_value); + + KUNIT_EXPECT_FALSE(test, per_pixel_alpha); + KUNIT_EXPECT_TRUE(test, pre_multiplied_alpha); + KUNIT_EXPECT_FALSE(test, global_alpha); + KUNIT_EXPECT_EQ(test, global_alpha_value, 0xff); +} + +/** + * dm_test_fill_blending_premulti_alpha_format() - Verify premultiplied alpha path. + * @test: KUnit test context. + * + * Verify if premultiplied mode enables per-pixel alpha for ARGB8888. + */ +static void dm_test_fill_blending_premulti_alpha_format(struct kunit *test) +{ + struct drm_plane_state state = { 0 }; + struct drm_framebuffer fb = { 0 }; + bool per_pixel_alpha; + bool pre_multiplied_alpha; + bool global_alpha; + int global_alpha_value; + + fb.format = drm_format_info(DRM_FORMAT_ARGB8888); + KUNIT_ASSERT_NOT_NULL(test, fb.format); + + state.fb = &fb; + state.pixel_blend_mode = DRM_MODE_BLEND_PREMULTI; + state.alpha = 0xffff; + + amdgpu_dm_plane_fill_blending_from_plane_state(&state, + &per_pixel_alpha, + &pre_multiplied_alpha, + &global_alpha, + &global_alpha_value); + + KUNIT_EXPECT_TRUE(test, per_pixel_alpha); + KUNIT_EXPECT_TRUE(test, pre_multiplied_alpha); + KUNIT_EXPECT_FALSE(test, global_alpha); + KUNIT_EXPECT_EQ(test, global_alpha_value, 0xff); +} + +/** + * dm_test_fill_blending_coverage_alpha_format() - Verify coverage mode behavior. + * @test: KUnit test context. + * + * Verify if coverage mode sets per-pixel alpha and disables + * pre_multiplied_alpha for ARGB8888. + */ +static void dm_test_fill_blending_coverage_alpha_format(struct kunit *test) +{ + struct drm_plane_state state = { 0 }; + struct drm_framebuffer fb = { 0 }; + bool per_pixel_alpha; + bool pre_multiplied_alpha; + bool global_alpha; + int global_alpha_value; + + fb.format = drm_format_info(DRM_FORMAT_ARGB8888); + KUNIT_ASSERT_NOT_NULL(test, fb.format); + + state.fb = &fb; + state.pixel_blend_mode = DRM_MODE_BLEND_COVERAGE; + state.alpha = 0xffff; + + amdgpu_dm_plane_fill_blending_from_plane_state(&state, + &per_pixel_alpha, + &pre_multiplied_alpha, + &global_alpha, + &global_alpha_value); + + KUNIT_EXPECT_TRUE(test, per_pixel_alpha); + KUNIT_EXPECT_FALSE(test, pre_multiplied_alpha); + KUNIT_EXPECT_FALSE(test, global_alpha); + KUNIT_EXPECT_EQ(test, global_alpha_value, 0xff); +} + +/** + * dm_test_fill_blending_global_alpha() - Verify global alpha conversion to 8 bits. + * @test: KUnit test context. + * + * Verify if global alpha is enabled and converted from 16-bit to 8-bit. + */ +static void dm_test_fill_blending_global_alpha(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_plane *plane; + struct drm_plane_state *state; + bool per_pixel_alpha; + bool pre_multiplied_alpha; + bool global_alpha; + int global_alpha_value; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, state); + + plane->dev = &adev->ddev; + state->plane = plane; + state->pixel_blend_mode = DRM_MODE_BLEND_PIXEL_NONE; + state->alpha = 0x8000; + + amdgpu_dm_plane_fill_blending_from_plane_state(state, + &per_pixel_alpha, + &pre_multiplied_alpha, + &global_alpha, + &global_alpha_value); + + KUNIT_EXPECT_FALSE(test, per_pixel_alpha); + KUNIT_EXPECT_TRUE(test, pre_multiplied_alpha); + KUNIT_EXPECT_TRUE(test, global_alpha); + KUNIT_EXPECT_EQ(test, global_alpha_value, 0x80); +} + +/** + * dm_test_modifier_has_dcc() - Verify helper detects AMD DCC modifiers. + * @test: KUnit test context. + * + * Verify if DCC detection works for linear and AMD DCC modifiers. + */ +static void dm_test_modifier_has_dcc(struct kunit *test) +{ + uint64_t dcc_mod = AMD_FMT_MOD | AMD_FMT_MOD_SET(DCC, 1); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_plane_modifier_has_dcc(DRM_FORMAT_MOD_LINEAR)); + KUNIT_EXPECT_TRUE(test, amdgpu_dm_plane_modifier_has_dcc(dcc_mod)); +} + +/** + * dm_test_modifier_gfx9_swizzle_mode() - Verify swizzle helper for linear and AMD modifiers. + * @test: KUnit test context. + * + * Verify if swizzle mode decoding works for linear and AMD tiled modifiers. + */ +static void dm_test_modifier_gfx9_swizzle_mode(struct kunit *test) +{ + uint64_t mod = AMD_FMT_MOD | AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X); + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_modifier_gfx9_swizzle_mode(DRM_FORMAT_MOD_LINEAR), 0U); + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_modifier_gfx9_swizzle_mode(mod), + (unsigned int)AMD_FMT_MOD_TILE_GFX9_64K_S_X); +} + +/** + * dm_test_get_plane_formats() - Verify plane format counts for key plane types. + * @test: KUnit test context. + * + * Verify if returned format counts match primary, overlay, and cursor planes. + */ +static void dm_test_get_plane_formats(struct kunit *test) +{ + struct drm_plane *plane; + struct dc_plane_cap *cap; + uint32_t formats[32] = {0}; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + cap = kunit_kzalloc(test, sizeof(*cap), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, cap); + + plane->type = DRM_PLANE_TYPE_PRIMARY; + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_get_plane_formats(plane, NULL, formats, 32), 14); + + cap->pixel_format_support.nv12 = true; + cap->pixel_format_support.p010 = true; + cap->pixel_format_support.fp16 = true; + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_get_plane_formats(plane, cap, formats, 32), 20); + + plane->type = DRM_PLANE_TYPE_OVERLAY; + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_get_plane_formats(plane, NULL, formats, 32), 9); + + plane->type = DRM_PLANE_TYPE_CURSOR; + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_get_plane_formats(plane, NULL, formats, 32), 1); +} + +/** + * dm_test_get_plane_modifiers() - Verify early-return and cursor modifier list. + * @test: KUnit test context. + * + * Verify if modifier list handling works for unsupported families and cursor planes. + */ +static void dm_test_get_plane_modifiers(struct kunit *test) +{ + struct amdgpu_device *adev; + uint64_t *mods = NULL; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->family = AMDGPU_FAMILY_SI; + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_get_plane_modifiers(adev, DRM_PLANE_TYPE_PRIMARY, &mods), + 0); + KUNIT_EXPECT_PTR_EQ(test, mods, NULL); + + adev->family = AMDGPU_FAMILY_NV; + KUNIT_ASSERT_EQ(test, + amdgpu_dm_plane_get_plane_modifiers(adev, DRM_PLANE_TYPE_CURSOR, &mods), + 0); + KUNIT_ASSERT_NOT_NULL(test, mods); + KUNIT_EXPECT_EQ(test, mods[0], DRM_FORMAT_MOD_LINEAR); + KUNIT_EXPECT_EQ(test, mods[1], DRM_FORMAT_MOD_INVALID); + kfree(mods); +} + +/** + * dm_test_fill_dc_scaling_info() - Verify basic error and success paths. + * @test: KUnit test context. + * + * Verify if scaling info rejects invalid sizes and accepts valid sizes. + */ +static void dm_test_fill_dc_scaling_info(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_plane_state state = {0}; + struct dc_scaling_info info = {0}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + state.src_w = 0; + state.src_h = 100 << 16; + state.crtc_w = 100; + state.crtc_h = 100; + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_fill_dc_scaling_info(adev, &state, &info), -EINVAL); + + state.src_w = 100 << 16; + state.src_h = 100 << 16; + state.crtc_w = 100; + state.crtc_h = 100; + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_fill_dc_scaling_info(adev, &state, &info), 0); +} + +/** + * dm_test_get_min_max_dc_plane_scaling() - Verify format-specific cap selection and 1->1000 conversion. + * @test: KUnit test context. + * + * Verify if min/max scaling values are correct for NV12 and XRGB8888 formats. + */ +static void dm_test_get_min_max_dc_plane_scaling(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct drm_framebuffer *fb; + int min_downscale = 0; + int max_upscale = 0; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, fb); + + adev->dm.dc = dc; + dc->caps.planes[0].max_upscale_factor.nv12 = 1; + dc->caps.planes[0].max_downscale_factor.nv12 = 1; + dc->caps.planes[0].max_upscale_factor.argb8888 = 1600; + dc->caps.planes[0].max_downscale_factor.argb8888 = 250; + + fb->format = drm_format_info(DRM_FORMAT_NV12); + KUNIT_ASSERT_NOT_NULL(test, fb->format); + amdgpu_dm_plane_get_min_max_dc_plane_scaling(&adev->ddev, fb, &min_downscale, &max_upscale); + KUNIT_EXPECT_EQ(test, min_downscale, 1000); + KUNIT_EXPECT_EQ(test, max_upscale, 1000); + + fb->format = drm_format_info(DRM_FORMAT_XRGB8888); + KUNIT_ASSERT_NOT_NULL(test, fb->format); + amdgpu_dm_plane_get_min_max_dc_plane_scaling(&adev->ddev, fb, &min_downscale, &max_upscale); + KUNIT_EXPECT_EQ(test, min_downscale, 250); + KUNIT_EXPECT_EQ(test, max_upscale, 1600); +} + +/** + * dm_test_fill_plane_buffer_attributes_gfx8() - Verify graphics path and GFX8 tiling fill. + * @test: KUnit test context. + * + * Verify if GFX8 plane buffer attributes and tiling fields are filled correctly. + */ +static void dm_test_fill_plane_buffer_attributes_gfx8(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_framebuffer *afb; + struct dc_tiling_info *tiling_info; + struct plane_size *plane_size; + struct dc_plane_dcc_param *dcc; + struct dc_plane_address *address; + uint64_t tiling_flags = 0; + int ret; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); + tiling_info = kunit_kzalloc(test, sizeof(*tiling_info), GFP_KERNEL); + plane_size = kunit_kzalloc(test, sizeof(*plane_size), GFP_KERNEL); + dcc = kunit_kzalloc(test, sizeof(*dcc), GFP_KERNEL); + address = kunit_kzalloc(test, sizeof(*address), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, afb); + KUNIT_ASSERT_NOT_NULL(test, tiling_info); + KUNIT_ASSERT_NOT_NULL(test, plane_size); + KUNIT_ASSERT_NOT_NULL(test, dcc); + KUNIT_ASSERT_NOT_NULL(test, address); + + adev->family = AMDGPU_FAMILY_SI; + afb->address = 0x12345000ULL; + afb->base.width = 1920; + afb->base.height = 1080; + afb->base.offsets[0] = 0x1000; + afb->base.pitches[0] = 7680; + afb->base.format = drm_format_info(DRM_FORMAT_XRGB8888); + KUNIT_ASSERT_NOT_NULL(test, afb->base.format); + + tiling_flags |= AMDGPU_TILING_SET(ARRAY_MODE, DC_ARRAY_1D_TILED_THIN1); + tiling_flags |= AMDGPU_TILING_SET(PIPE_CONFIG, 5); + + ret = amdgpu_dm_plane_fill_plane_buffer_attributes(adev, afb, + SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, ROTATION_ANGLE_0, + tiling_flags, tiling_info, plane_size, dcc, address, true); + + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, plane_size->surface_size.width, 1920); + KUNIT_EXPECT_EQ(test, plane_size->surface_size.height, 1080); + KUNIT_EXPECT_EQ(test, plane_size->surface_pitch, 1920); + KUNIT_EXPECT_EQ(test, address->type, (int)PLN_ADDR_TYPE_GRAPHICS); + KUNIT_EXPECT_TRUE(test, address->tmz_surface); + KUNIT_EXPECT_EQ(test, (int)tiling_info->gfx8.array_mode, (int)DC_ARRAY_1D_TILED_THIN1); + KUNIT_EXPECT_EQ(test, tiling_info->gfx8.pipe_config, 5U); +} + +/** + * dm_test_get_cursor_position() - Verify cursor clipping and off-screen handling. + * @test: KUnit test context. + * + * Verify if cursor clipping, hotspot adjustment, and off-screen disable behavior work. + */ +static void dm_test_get_cursor_position(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_crtc *amdgpu_crtc; + struct drm_plane *plane; + struct drm_plane_state *state; + struct drm_framebuffer *fb; + struct dc_cursor_position position = {0}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + amdgpu_crtc = kunit_kzalloc(test, sizeof(*amdgpu_crtc), GFP_KERNEL); + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, amdgpu_crtc); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, fb); + + adev->ip_versions[DCE_HWIP][0] = IP_VERSION(4, 0, 0); + amdgpu_crtc->max_cursor_width = 64; + amdgpu_crtc->max_cursor_height = 64; + + plane->dev = &adev->ddev; + plane->state = state; + state->fb = fb; + state->crtc_x = -5; + state->crtc_y = -7; + state->crtc_w = 32; + state->crtc_h = 32; + + KUNIT_ASSERT_EQ(test, + amdgpu_dm_plane_get_cursor_position(plane, &amdgpu_crtc->base, &position), + 0); + KUNIT_EXPECT_TRUE(test, position.enable); + KUNIT_EXPECT_EQ(test, position.x, 0); + KUNIT_EXPECT_EQ(test, position.y, 0); + KUNIT_EXPECT_EQ(test, position.x_hotspot, 5); + KUNIT_EXPECT_EQ(test, position.y_hotspot, 7); + KUNIT_EXPECT_TRUE(test, position.translate_by_source); + + memset(&position, 0, sizeof(position)); + state->crtc_x = -64; + state->crtc_y = 0; + KUNIT_ASSERT_EQ(test, + amdgpu_dm_plane_get_cursor_position(plane, &amdgpu_crtc->base, &position), + 0); + KUNIT_EXPECT_FALSE(test, position.enable); +} + +/** + * dm_test_format_mod_supported() - Verify key format/modifier acceptance and rejection paths. + * @test: KUnit test context. + * + * Verify if format-modifier support checks match accepted and rejected cases. + */ +static void dm_test_format_mod_supported(struct kunit *test) +{ + struct amdgpu_device *adev; + struct drm_plane *plane; + uint64_t listed_mod; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, plane); + + adev->family = AMDGPU_FAMILY_NV; + plane->dev = &adev->ddev; + + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_XRGB8888, + DRM_FORMAT_MOD_LINEAR)); + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_XRGB8888, + DRM_FORMAT_MOD_INVALID)); + + KUNIT_EXPECT_FALSE(test, + amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_XRGB8888, + DRM_FORMAT_MOD_VENDOR_AMD)); + + listed_mod = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX9) | + AMD_FMT_MOD_SET(DCC, 1); + plane->modifiers = &listed_mod; + plane->modifier_count = 1; + + KUNIT_EXPECT_FALSE(test, + amdgpu_dm_plane_format_mod_supported(plane, DRM_FORMAT_NV12, listed_mod)); +} + +/** + * dm_test_fill_gfx12_plane_attributes_from_modifiers() - Verify GFX12 DCC mapping path. + * @test: KUnit test context. + * + * Verify if GFX12 modifier parsing enables DCC and sets expected DCC block mode. + */ +static void dm_test_fill_gfx12_plane_attributes_from_modifiers(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct amdgpu_framebuffer *afb; + struct plane_size plane_size = {0}; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct dm_test_dcc_cap_ctx ctx = { + .callback_ret = true, + .capable = true, + .output_independent_64b_blks = false, + }; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, dc); + KUNIT_ASSERT_NOT_NULL(test, afb); + + adev->family = AMDGPU_FAMILY_GC_12_0_0; + adev->dm.dc = dc; + adev->gfx.config.gb_addr_config_fields.num_pipes = 2; + adev->gfx.config.gb_addr_config_fields.num_banks = 4; + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 256; + adev->gfx.config.gb_addr_config_fields.num_se = 1; + adev->gfx.config.gb_addr_config_fields.max_compress_frags = 2; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 1; + dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; + dm_test_dcc_ctx = &ctx; + + afb->base.modifier = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX12_64K_2D) | + AMD_FMT_MOD_SET(TILE_VERSION, AMD_FMT_MOD_TILE_VER_GFX12) | + AMD_FMT_MOD_SET(DCC, 1) | + AMD_FMT_MOD_SET(DCC_MAX_COMPRESSED_BLOCK, 1); + plane_size.surface_size.width = 1920; + plane_size.surface_size.height = 1080; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers( + adev, afb, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + ROTATION_ANGLE_0, &plane_size, &tiling_info, &dcc, &address), + 0); + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxAddr3); + KUNIT_EXPECT_TRUE(test, dcc.enable); + KUNIT_EXPECT_EQ(test, (int)dcc.dcc_ind_blk, (int)hubp_ind_block_128b); + + dm_test_dcc_ctx = NULL; +} + +/** + * dm_test_fill_gfx9_plane_attributes_from_modifiers() - Verify basic GFX9 linear modifier path. + * @test: KUnit test context. + * + * Verify if GFX9 linear modifier handling keeps DCC disabled. + */ +static void dm_test_fill_gfx9_plane_attributes_from_modifiers(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_framebuffer *afb; + struct plane_size plane_size = {0}; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + afb = kunit_kzalloc(test, sizeof(*afb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, afb); + + adev->family = AMDGPU_FAMILY_NV; + adev->gfx.config.gb_addr_config_fields.num_pipes = 2; + adev->gfx.config.gb_addr_config_fields.num_banks = 4; + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 256; + adev->gfx.config.gb_addr_config_fields.num_se = 1; + adev->gfx.config.gb_addr_config_fields.max_compress_frags = 2; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 1; + adev->gfx.config.gb_addr_config_fields.num_pkrs = 2; + adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0); + + afb->base.modifier = DRM_FORMAT_MOD_LINEAR; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_fill_gfx9_plane_attributes_from_modifiers( + adev, afb, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + ROTATION_ANGLE_0, &plane_size, &tiling_info, &dcc, &address), + 0); + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxVersion9); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.swizzle, 0U); + KUNIT_EXPECT_FALSE(test, dcc.enable); +} + +/** + * dm_test_helper_check_state_viewport_reject() - Verify viewport outside screen rejects state. + * @test: KUnit test context. + * + * Verify if plane state is rejected when the viewport is outside display bounds. + */ +static void dm_test_helper_check_state_viewport_reject(struct kunit *test) +{ + struct drm_plane *plane; + struct drm_plane_state *state; + struct drm_crtc *crtc; + struct drm_crtc_state *new_crtc_state; + struct drm_framebuffer *fb; + + plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + crtc = kunit_kzalloc(test, sizeof(*crtc), GFP_KERNEL); + new_crtc_state = kunit_kzalloc(test, sizeof(*new_crtc_state), GFP_KERNEL); + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, plane); + KUNIT_ASSERT_NOT_NULL(test, state); + KUNIT_ASSERT_NOT_NULL(test, crtc); + KUNIT_ASSERT_NOT_NULL(test, new_crtc_state); + KUNIT_ASSERT_NOT_NULL(test, fb); + + plane->type = DRM_PLANE_TYPE_OVERLAY; + state->plane = plane; + state->fb = fb; + state->crtc = crtc; + state->crtc_x = 200; + state->crtc_y = 0; + state->crtc_w = 100; + state->crtc_h = 100; + new_crtc_state->mode.crtc_hdisplay = 100; + new_crtc_state->mode.crtc_vdisplay = 100; + + KUNIT_EXPECT_EQ(test, amdgpu_dm_plane_helper_check_state(state, new_crtc_state), -EINVAL); +} + +/** + * dm_test_validate_dcc_disabled_returns_success() - Verify disabled DCC is accepted. + * @test: KUnit test context. + * + * Verify if DCC validation succeeds when DCC is disabled. + */ +static void dm_test_validate_dcc_disabled_returns_success(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct plane_size plane_size = {0}; + + dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, + &plane_size, test); + dcc.enable = 0; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + ROTATION_ANGLE_0, &tiling_info, &dcc, + &address, &plane_size), + 0); +} + +/** + * dm_test_validate_dcc_video_non_gfx12_fails() - Verify video format restriction on pre-GFX12. + * @test: KUnit test context. + * + * Verify if video format DCC validation fails on non-GFX12 devices. + */ +static void dm_test_validate_dcc_video_non_gfx12_fails(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct plane_size plane_size = {0}; + + dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, + &plane_size, test); + adev->family = AMDGPU_FAMILY_NV; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + ROTATION_ANGLE_0, &tiling_info, &dcc, + &address, &plane_size), + -EINVAL); +} + +/** + * dm_test_validate_dcc_missing_cap_func_fails() - Verify missing capability callback fails. + * @test: KUnit test context. + * + * Verify if validation fails when DCC capability callback is not provided. + */ +static void dm_test_validate_dcc_missing_cap_func_fails(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct plane_size plane_size = {0}; + + dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, + &plane_size, test); + dc->cap_funcs.get_dcc_compression_cap = NULL; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + ROTATION_ANGLE_0, &tiling_info, &dcc, + &address, &plane_size), + -EINVAL); +} + +/** + * dm_test_validate_dcc_success_and_scan_mapping() - Verify success path and rotation-to-scan mapping. + * @test: KUnit test context. + * + * Verify if DCC validation succeeds and rotation-to-scan mapping is correct. + */ +static void dm_test_validate_dcc_success_and_scan_mapping(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct plane_size plane_size = {0}; + struct dm_test_dcc_cap_ctx ctx = { + .callback_ret = true, + .capable = true, + .output_independent_64b_blks = true, + }; + + dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, + &plane_size, test); + dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; + dm_test_dcc_ctx = &ctx; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + ROTATION_ANGLE_90, &tiling_info, &dcc, + &address, &plane_size), + 0); + KUNIT_EXPECT_TRUE(test, ctx.called); + KUNIT_EXPECT_EQ(test, (int)ctx.captured_input.scan, (int)SCAN_DIRECTION_VERTICAL); + KUNIT_EXPECT_EQ(test, (int)ctx.captured_input.format, + (int)SURFACE_PIXEL_FORMAT_GRPH_ARGB8888); + + dm_test_dcc_ctx = NULL; +} + +/** + * dm_test_validate_dcc_independent_64b_mismatch_fails() - Verify 64B compatibility check. + * @test: KUnit test context. + * + * Verify if validation fails when independent_64b_blks values do not match. + */ +static void dm_test_validate_dcc_independent_64b_mismatch_fails(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc *dc; + struct dc_tiling_info tiling_info = {0}; + struct dc_plane_dcc_param dcc = {0}; + struct dc_plane_address address = {0}; + struct plane_size plane_size = {0}; + struct dm_test_dcc_cap_ctx ctx = { + .callback_ret = true, + .capable = true, + .output_independent_64b_blks = true, + }; + + dm_test_init_validate_dcc_inputs(&adev, &dc, &tiling_info, &dcc, &address, + &plane_size, test); + dcc.independent_64b_blks = 0; + dc->cap_funcs.get_dcc_compression_cap = dm_test_get_dcc_compression_cap; + dm_test_dcc_ctx = &ctx; + + KUNIT_EXPECT_EQ(test, + amdgpu_dm_plane_validate_dcc(adev, SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + ROTATION_ANGLE_0, &tiling_info, &dcc, + &address, &plane_size), + -EINVAL); + + dm_test_dcc_ctx = NULL; +} + +/** + * dm_test_add_modifier_appends_value() - Verify one modifier append. + * @test: KUnit test context. + * + * Verify if a modifier is appended and size is updated. + */ +static void dm_test_add_modifier_appends_value(struct kunit *test) +{ + uint64_t size = 0; + uint64_t cap = 2; + uint64_t *mods = kmalloc_array(cap, sizeof(*mods), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, mods); + + amdgpu_dm_plane_add_modifier(&mods, &size, &cap, 0x1234ULL); + + KUNIT_ASSERT_NOT_NULL(test, mods); + KUNIT_EXPECT_EQ(test, size, 1ULL); + KUNIT_EXPECT_EQ(test, cap, 2ULL); + KUNIT_EXPECT_EQ(test, mods[0], 0x1234ULL); + + kfree(mods); +} + +/** + * dm_test_add_modifier_grows_capacity() - Verify add triggers growth and preserves old data. + * @test: KUnit test context. + * + * Verify if modifier array growth keeps old data and appends new data. + */ +static void dm_test_add_modifier_grows_capacity(struct kunit *test) +{ + uint64_t size = 1; + uint64_t cap = 1; + uint64_t *mods = kmalloc_array(cap, sizeof(*mods), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, mods); + mods[0] = 0xAAULL; + + amdgpu_dm_plane_add_modifier(&mods, &size, &cap, 0xBBULL); + + KUNIT_ASSERT_NOT_NULL(test, mods); + KUNIT_EXPECT_EQ(test, cap, 2ULL); + KUNIT_EXPECT_EQ(test, size, 2ULL); + KUNIT_EXPECT_EQ(test, mods[0], 0xAAULL); + KUNIT_EXPECT_EQ(test, mods[1], 0xBBULL); + + kfree(mods); +} + +/** + * dm_test_add_modifier_noop_when_mods_null() - Verify helper is a no-op on NULL mods list. + * @test: KUnit test context. + * + * Verify if add_modifier does nothing when the modifier list is NULL. + */ +static void dm_test_add_modifier_noop_when_mods_null(struct kunit *test) +{ + uint64_t size = 3; + uint64_t cap = 7; + uint64_t *mods = NULL; + + amdgpu_dm_plane_add_modifier(&mods, &size, &cap, 0x55ULL); + + KUNIT_EXPECT_PTR_EQ(test, mods, NULL); + KUNIT_EXPECT_EQ(test, size, 3ULL); + KUNIT_EXPECT_EQ(test, cap, 7ULL); +} + +/** + * dm_test_fill_gfx8_tiling_info_2d_tiled() - Verify GFX8 2D tiled flag parsing. + * @test: KUnit test context. + * + * Verify if 2D tiled GFX8 flags populate expected tiling fields. + */ +static void dm_test_fill_gfx8_tiling_info_2d_tiled(struct kunit *test) +{ + struct dc_tiling_info tiling_info = {0}; + uint64_t tiling_flags = 0; + + tiling_flags |= AMDGPU_TILING_SET(ARRAY_MODE, DC_ARRAY_2D_TILED_THIN1); + tiling_flags |= AMDGPU_TILING_SET(BANK_WIDTH, 2); + tiling_flags |= AMDGPU_TILING_SET(BANK_HEIGHT, 1); + tiling_flags |= AMDGPU_TILING_SET(MACRO_TILE_ASPECT, 3); + tiling_flags |= AMDGPU_TILING_SET(TILE_SPLIT, 4); + tiling_flags |= AMDGPU_TILING_SET(NUM_BANKS, 2); + tiling_flags |= AMDGPU_TILING_SET(PIPE_CONFIG, 7); + + amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(&tiling_info, tiling_flags); + + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfxversion, (int)DcGfxVersion8); + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.array_mode, (int)DC_ARRAY_2D_TILED_THIN1); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.bank_width, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.bank_height, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.tile_aspect, 3U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.tile_split, 4U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.num_banks, 2U); + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.tile_mode, + (int)DC_ADDR_SURF_MICRO_TILING_DISPLAY); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.pipe_config, 7U); +} + +/** + * dm_test_fill_gfx8_tiling_info_1d_tiled() - Verify GFX8 1D tiled flag parsing. + * @test: KUnit test context. + * + * Verify if 1D tiled GFX8 flags populate array mode and pipe config. + */ +static void dm_test_fill_gfx8_tiling_info_1d_tiled(struct kunit *test) +{ + struct dc_tiling_info tiling_info = {0}; + uint64_t tiling_flags = 0; + + tiling_flags |= AMDGPU_TILING_SET(ARRAY_MODE, DC_ARRAY_1D_TILED_THIN1); + tiling_flags |= AMDGPU_TILING_SET(PIPE_CONFIG, 5); + + amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(&tiling_info, tiling_flags); + + KUNIT_EXPECT_EQ(test, (int)tiling_info.gfx8.array_mode, (int)DC_ARRAY_1D_TILED_THIN1); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.pipe_config, 5U); +} + +/** + * dm_test_fill_gfx8_tiling_info_other_mode() - Verify non-1D/non-2D mode handling. + * @test: KUnit test context. + * + * Verify if unsupported array mode keeps preset fields and updates pipe config. + */ +static void dm_test_fill_gfx8_tiling_info_other_mode(struct kunit *test) +{ + struct dc_tiling_info tiling_info = {0}; + uint64_t tiling_flags = 0; + + tiling_info.gfxversion = 0x7f; + tiling_info.gfx8.array_mode = 0x7f; + tiling_info.gfx8.tile_mode = 0x7f; + tiling_info.gfx8.num_banks = 0x7f; + + tiling_flags |= AMDGPU_TILING_SET(PIPE_CONFIG, 6); + + amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags(&tiling_info, tiling_flags); + + KUNIT_EXPECT_EQ(test, tiling_info.gfxversion, 0x7f); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.array_mode, 0x7f); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.tile_mode, 0x7f); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.num_banks, 0x7f); + KUNIT_EXPECT_EQ(test, tiling_info.gfx8.pipe_config, 6U); +} + +/** + * dm_test_fill_gfx9_tiling_info_from_device_pre_10_3() - Verify GFX9 field copy before 10.3. + * @test: KUnit test context. + * + * Verify if pre-10.3 device fields are copied and existing num_pkrs is kept. + */ +static void dm_test_fill_gfx9_tiling_info_from_device_pre_10_3(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_tiling_info tiling_info = {0}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->gfx.config.gb_addr_config_fields.num_pipes = 4; + adev->gfx.config.gb_addr_config_fields.num_banks = 8; + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 256; + adev->gfx.config.gb_addr_config_fields.num_se = 2; + adev->gfx.config.gb_addr_config_fields.max_compress_frags = 1; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 2; + adev->gfx.config.gb_addr_config_fields.num_pkrs = 3; + adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 2, 9); + + tiling_info.gfx9.num_pkrs = 0x5a; + + amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(adev, &tiling_info); + + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pipes, 4U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_banks, 8U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.pipe_interleave, 256U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_shader_engines, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.max_compressed_frags, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_rb_per_se, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 0x5aU); +} + +/** + * dm_test_fill_gfx9_tiling_info_from_device_10_3_plus() - Verify num_pkrs update on 10.3+. + * @test: KUnit test context. + * + * Verify if 10.3+ device fields are copied and num_pkrs is updated. + */ +static void dm_test_fill_gfx9_tiling_info_from_device_10_3_plus(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_tiling_info tiling_info = {0}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->gfx.config.gb_addr_config_fields.num_pipes = 2; + adev->gfx.config.gb_addr_config_fields.num_banks = 4; + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 128; + adev->gfx.config.gb_addr_config_fields.num_se = 1; + adev->gfx.config.gb_addr_config_fields.max_compress_frags = 2; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 1; + adev->gfx.config.gb_addr_config_fields.num_pkrs = 6; + adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0); + + amdgpu_dm_plane_fill_gfx9_tiling_info_from_device(adev, &tiling_info); + + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pipes, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_banks, 4U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.pipe_interleave, 128U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_shader_engines, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.max_compressed_frags, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_rb_per_se, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 6U); +} + +/** + * dm_test_fill_gfx9_tiling_info_from_modifier_linear() - Verify non-AMD modifier keeps device values. + * @test: KUnit test context. + * + * Verify if linear modifier path keeps values from device configuration. + */ +static void dm_test_fill_gfx9_tiling_info_from_modifier_linear(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_tiling_info tiling_info = {0}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->family = AMDGPU_FAMILY_NV; + adev->gfx.config.gb_addr_config_fields.num_pipes = 4; + adev->gfx.config.gb_addr_config_fields.num_banks = 8; + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 256; + adev->gfx.config.gb_addr_config_fields.num_se = 2; + adev->gfx.config.gb_addr_config_fields.max_compress_frags = 1; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 2; + adev->gfx.config.gb_addr_config_fields.num_pkrs = 3; + adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0); + + amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(adev, &tiling_info, + DRM_FORMAT_MOD_LINEAR); + + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pipes, 4U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_banks, 8U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.pipe_interleave, 256U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_shader_engines, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.max_compressed_frags, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_rb_per_se, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 3U); +} + +/** + * dm_test_fill_gfx9_tiling_info_from_modifier_pre_nv() - Verify AMD modifier updates banks on pre-NV. + * @test: KUnit test context. + * + * Verify if AMD modifier updates pre-NV pipe, engine, and bank fields. + */ +static void dm_test_fill_gfx9_tiling_info_from_modifier_pre_nv(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_tiling_info tiling_info = {0}; + uint64_t modifier; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->family = AMDGPU_FAMILY_RV; + adev->gfx.config.gb_addr_config_fields.num_pipes = 4; + adev->gfx.config.gb_addr_config_fields.num_banks = 16; + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 256; + adev->gfx.config.gb_addr_config_fields.num_se = 2; + adev->gfx.config.gb_addr_config_fields.max_compress_frags = 1; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 2; + adev->gfx.config.gb_addr_config_fields.num_pkrs = 7; + adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 2, 9); + + tiling_info.gfx9.num_pkrs = 0x5a; + + modifier = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, 7) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, 3) | + AMD_FMT_MOD_SET(PACKERS, 2); + + amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(adev, &tiling_info, modifier); + + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pipes, 32U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_shader_engines, 4U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_banks, 8U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 0x5aU); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); +} + +/** + * dm_test_fill_gfx9_tiling_info_from_modifier_nv() - Verify AMD modifier updates packers on NV+. + * @test: KUnit test context. + * + * Verify if AMD modifier updates NV+ pipe, engine, and packer fields. + */ +static void dm_test_fill_gfx9_tiling_info_from_modifier_nv(struct kunit *test) +{ + struct amdgpu_device *adev; + struct dc_tiling_info tiling_info = {0}; + uint64_t modifier; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->family = AMDGPU_FAMILY_NV; + adev->gfx.config.gb_addr_config_fields.num_pipes = 2; + adev->gfx.config.gb_addr_config_fields.num_banks = 9; + adev->gfx.config.gb_addr_config_fields.pipe_interleave_size = 128; + adev->gfx.config.gb_addr_config_fields.num_se = 1; + adev->gfx.config.gb_addr_config_fields.max_compress_frags = 2; + adev->gfx.config.gb_addr_config_fields.num_rb_per_se = 1; + adev->gfx.config.gb_addr_config_fields.num_pkrs = 2; + adev->ip_versions[GC_HWIP][0] = IP_VERSION(10, 3, 0); + + modifier = AMD_FMT_MOD | + AMD_FMT_MOD_SET(TILE, AMD_FMT_MOD_TILE_GFX9_64K_S_X) | + AMD_FMT_MOD_SET(PIPE_XOR_BITS, 6) | + AMD_FMT_MOD_SET(BANK_XOR_BITS, 2) | + AMD_FMT_MOD_SET(PACKERS, 3); + + amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier(adev, &tiling_info, modifier); + + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pipes, 32U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_shader_engines, 2U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_banks, 9U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.num_pkrs, 8U); + KUNIT_EXPECT_EQ(test, tiling_info.gfx9.shaderEnable, 1U); +} + +static struct kunit_case amdgpu_dm_plane_test_cases[] = { + /* amdgpu_dm_plane_is_video_format() */ + KUNIT_CASE(dm_test_plane_is_video_format_known_video), + /* amdgpu_dm_plane_fill_blending_from_plane_state() */ + KUNIT_CASE(dm_test_fill_blending_defaults), + KUNIT_CASE(dm_test_fill_blending_premulti_alpha_format), + KUNIT_CASE(dm_test_fill_blending_coverage_alpha_format), + KUNIT_CASE(dm_test_fill_blending_global_alpha), + /* amdgpu_dm_plane_modifier_* helpers() */ + KUNIT_CASE(dm_test_modifier_has_dcc), + KUNIT_CASE(dm_test_modifier_gfx9_swizzle_mode), + /* amdgpu_dm_plane_get_plane_formats() */ + KUNIT_CASE(dm_test_get_plane_formats), + /* amdgpu_dm_plane_get_plane_modifiers() */ + KUNIT_CASE(dm_test_get_plane_modifiers), + /* amdgpu_dm_plane_fill_dc_scaling_info() */ + KUNIT_CASE(dm_test_fill_dc_scaling_info), + /* amdgpu_dm_plane_get_min_max_dc_plane_scaling() */ + KUNIT_CASE(dm_test_get_min_max_dc_plane_scaling), + /* amdgpu_dm_plane_fill_plane_buffer_attributes() */ + KUNIT_CASE(dm_test_fill_plane_buffer_attributes_gfx8), + /* amdgpu_dm_plane_get_cursor_position() */ + KUNIT_CASE(dm_test_get_cursor_position), + /* amdgpu_dm_plane_format_mod_supported() */ + KUNIT_CASE(dm_test_format_mod_supported), + /* amdgpu_dm_plane_fill_gfx12_plane_attributes_from_modifiers() */ + KUNIT_CASE(dm_test_fill_gfx12_plane_attributes_from_modifiers), + /* amdgpu_dm_plane_fill_gfx9_plane_attributes_from_modifiers() */ + KUNIT_CASE(dm_test_fill_gfx9_plane_attributes_from_modifiers), + /* amdgpu_dm_plane_helper_check_state() */ + KUNIT_CASE(dm_test_helper_check_state_viewport_reject), + /* amdgpu_dm_plane_add_modifier() */ + KUNIT_CASE(dm_test_add_modifier_appends_value), + KUNIT_CASE(dm_test_add_modifier_grows_capacity), + KUNIT_CASE(dm_test_add_modifier_noop_when_mods_null), + /* amdgpu_dm_plane_fill_gfx8_tiling_info_from_flags() */ + KUNIT_CASE(dm_test_fill_gfx8_tiling_info_2d_tiled), + KUNIT_CASE(dm_test_fill_gfx8_tiling_info_1d_tiled), + KUNIT_CASE(dm_test_fill_gfx8_tiling_info_other_mode), + /* amdgpu_dm_plane_fill_gfx9_tiling_info_from_device() */ + KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_device_pre_10_3), + KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_device_10_3_plus), + /* amdgpu_dm_plane_fill_gfx9_tiling_info_from_modifier() */ + KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier_linear), + KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier_pre_nv), + KUNIT_CASE(dm_test_fill_gfx9_tiling_info_from_modifier_nv), + /* amdgpu_dm_plane_validate_dcc() */ + KUNIT_CASE(dm_test_validate_dcc_disabled_returns_success), + KUNIT_CASE(dm_test_validate_dcc_video_non_gfx12_fails), + KUNIT_CASE(dm_test_validate_dcc_missing_cap_func_fails), + KUNIT_CASE(dm_test_validate_dcc_success_and_scan_mapping), + KUNIT_CASE(dm_test_validate_dcc_independent_64b_mismatch_fails), + {} +}; + +static struct kunit_suite amdgpu_dm_plane_test_suite = { + .name = "amdgpu_dm_plane", + .test_cases = amdgpu_dm_plane_test_cases, +}; + +kunit_test_suite(amdgpu_dm_plane_test_suite); + +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_plane"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_pp_smu_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_pp_smu_test.c new file mode 100644 index 000000000000..8d1d26bfcc16 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_pp_smu_test.c @@ -0,0 +1,2454 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_pp_smu.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include +#include +#include + +#include "dc.h" +#include "dm_services.h" +#include "dm_pp_smu.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_pp_smu.h" + +/* ---- Stub DPM layer ---- */ + +/** + * struct stub_dpm_context - Tracks stub DPM callback invocations + * @ret_val: Return value for the next DPM callback + * @get_current_clocks_info: Clock info returned by stub get_current_clocks + * @get_clock_by_type_clocks: Clocks returned by stub get_clock_by_type + * @get_validation_clks: Validation clocks returned by stub + * @get_clock_by_type_with_latency_clks: Returned by stub with_latency + * @get_clock_by_type_with_voltage_clks: Returned by stub with_voltage + * @set_watermarks_ret: Return value for set_watermarks + * @display_clock_voltage_ret: Return value for display_clock_voltage_request + * @display_disable_memory_clock_switch_ret: Return for disable_memory_clock + * @get_max_sustainable_ret: Return for get_max_sustainable_clocks_by_dc + * @get_uclk_dpm_ret: Return for get_uclk_dpm_states + * @get_dpm_clock_table_ret: Return for get_dpm_clock_table + * @set_active_display_count_ret: Return for set_active_display_count + * @set_min_deep_sleep_dcefclk_ret: Return for set_min_deep_sleep_dcefclk + * @get_validation_clks_ret: Return for get_display_mode_validation_clocks + */ +struct stub_dpm_context { + int ret_val; + struct amd_pp_clock_info get_current_clocks_info; + struct amd_pp_clocks get_clock_by_type_clocks; + struct amd_pp_simple_clock_info get_validation_clks; + int get_validation_clks_ret; + struct pp_clock_levels_with_latency get_clock_by_type_with_latency_clks; + struct pp_clock_levels_with_voltage get_clock_by_type_with_voltage_clks; + int set_watermarks_ret; + int display_clock_voltage_ret; + int display_disable_memory_clock_switch_ret; + int get_max_sustainable_ret; + int get_uclk_dpm_ret; + int get_dpm_clock_table_ret; + int set_active_display_count_ret; + int set_min_deep_sleep_dcefclk_ret; +}; + +static struct stub_dpm_context *stub_dpm_ctx; + +static int stub_get_current_clocks(void *handle, struct amd_pp_clock_info *clocks) +{ + if (stub_dpm_ctx->ret_val) + return stub_dpm_ctx->ret_val; + *clocks = stub_dpm_ctx->get_current_clocks_info; + return 0; +} + +static int stub_get_clock_by_type(void *handle, enum amd_pp_clock_type type, + struct amd_pp_clocks *clocks) +{ + if (stub_dpm_ctx->ret_val) + return stub_dpm_ctx->ret_val; + *clocks = stub_dpm_ctx->get_clock_by_type_clocks; + return 0; +} + +static int stub_get_display_mode_validation_clocks(void *handle, + struct amd_pp_simple_clock_info *clocks) +{ + if (stub_dpm_ctx->get_validation_clks_ret) + return stub_dpm_ctx->get_validation_clks_ret; + *clocks = stub_dpm_ctx->get_validation_clks; + return 0; +} + +static int stub_get_clock_by_type_with_latency(void *handle, + enum amd_pp_clock_type type, + struct pp_clock_levels_with_latency *clocks) +{ + if (stub_dpm_ctx->ret_val) + return stub_dpm_ctx->ret_val; + *clocks = stub_dpm_ctx->get_clock_by_type_with_latency_clks; + return 0; +} + +static int stub_get_clock_by_type_with_voltage(void *handle, + enum amd_pp_clock_type type, + struct pp_clock_levels_with_voltage *clocks) +{ + if (stub_dpm_ctx->ret_val) + return stub_dpm_ctx->ret_val; + *clocks = stub_dpm_ctx->get_clock_by_type_with_voltage_clks; + return 0; +} + +static void stub_display_configuration_change(void *handle) +{ + /* No-op: satisfies display_configuration_changed callback */ +} + +static void stub_pm_compute_clocks(void *handle) +{ + /* No-op: satisfies pm_compute_clocks callback */ +} + +static int stub_set_watermarks_for_clocks_ranges(void *handle, void *clock_ranges) +{ + return stub_dpm_ctx->set_watermarks_ret; +} + +static int stub_display_clock_voltage_request(void *handle, + struct pp_display_clock_request *clock) +{ + return stub_dpm_ctx->display_clock_voltage_ret; +} + +static int stub_set_active_display_count(void *handle, uint32_t count) +{ + return stub_dpm_ctx->set_active_display_count_ret; +} + +static int stub_set_min_deep_sleep_dcefclk(void *handle, uint32_t clock) +{ + return stub_dpm_ctx->set_min_deep_sleep_dcefclk_ret; +} + +static int stub_set_hard_min_dcefclk_by_freq(void *handle, uint32_t clock) +{ + return 0; +} + +static int stub_set_hard_min_fclk_by_freq(void *handle, uint32_t clock) +{ + return 0; +} + +static int stub_notify_smu_enable_pwe(void *handle) +{ + return 0; +} + +static int stub_display_disable_memory_clock_switch(void *handle, + bool disable_memory_clock_switch) +{ + return stub_dpm_ctx->display_disable_memory_clock_switch_ret; +} + +static int stub_get_max_sustainable_clocks_by_dc(void *handle, + struct pp_smu_nv_clock_table *max_clocks) +{ + return stub_dpm_ctx->get_max_sustainable_ret; +} + +static int stub_get_uclk_dpm_states(void *handle, + unsigned int *clock_values_in_khz, + unsigned int *num_states) +{ + return stub_dpm_ctx->get_uclk_dpm_ret; +} + +static int stub_get_dpm_clock_table(void *handle, struct dpm_clocks *clock_table) +{ + return stub_dpm_ctx->get_dpm_clock_table_ret; +} + +static const struct amd_pm_funcs stub_pp_funcs = { + .get_current_clocks = stub_get_current_clocks, + .get_clock_by_type = stub_get_clock_by_type, + .get_display_mode_validation_clocks = stub_get_display_mode_validation_clocks, + .get_clock_by_type_with_latency = stub_get_clock_by_type_with_latency, + .get_clock_by_type_with_voltage = stub_get_clock_by_type_with_voltage, + .display_configuration_changed = stub_display_configuration_change, + .pm_compute_clocks = stub_pm_compute_clocks, + .set_watermarks_for_clocks_ranges = stub_set_watermarks_for_clocks_ranges, + .display_clock_voltage_request = stub_display_clock_voltage_request, + .set_active_display_count = stub_set_active_display_count, + .set_min_deep_sleep_dcefclk = stub_set_min_deep_sleep_dcefclk, + .set_hard_min_dcefclk_by_freq = stub_set_hard_min_dcefclk_by_freq, + .set_hard_min_fclk_by_freq = stub_set_hard_min_fclk_by_freq, + .notify_smu_enable_pwe = stub_notify_smu_enable_pwe, + .display_disable_memory_clock_switch = stub_display_disable_memory_clock_switch, + .get_max_sustainable_clocks_by_dc = stub_get_max_sustainable_clocks_by_dc, + .get_uclk_dpm_states = stub_get_uclk_dpm_states, + .get_dpm_clock_table = stub_get_dpm_clock_table, +}; + +/** + * setup_stub_dpm - Initialize a stub DPM environment for testing + * @test: KUnit test context + * @adev: Pointer to amdgpu_device to configure + * + * Sets up adev->powerplay.pp_funcs and initializes adev->pm.mutex so that + * amdgpu_dpm_* functions can be safely called with stub callbacks. + */ +static void setup_stub_dpm(struct kunit *test, struct amdgpu_device *adev) +{ + stub_dpm_ctx = kunit_kzalloc(test, sizeof(*stub_dpm_ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, stub_dpm_ctx); + + adev->powerplay.pp_funcs = &stub_pp_funcs; + adev->powerplay.pp_handle = adev; + mutex_init(&adev->pm.mutex); +} + +/* ---- Tests for get_default_clock_levels ---- */ + +/** + * dm_test_default_clock_levels_display - Test display clock default levels + * @test: KUnit test context + * + * Verify that get_default_clock_levels populates 6 display clock levels + * with the expected frequencies in kHz. + */ +static void dm_test_default_clock_levels_display(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + uint32_t expected[] = { 300000, 400000, 496560, 626090, 685720, 757900 }; + int i; + + get_default_clock_levels(DM_PP_CLOCK_TYPE_DISPLAY_CLK, &clks); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 6U); + for (i = 0; i < 6; i++) + KUNIT_EXPECT_EQ(test, clks.clocks_in_khz[i], expected[i]); +} + +/** + * dm_test_default_clock_levels_engine - Test engine clock default levels + * @test: KUnit test context + * + * Verify that get_default_clock_levels populates 6 engine clock levels + * with the expected frequencies in kHz. + */ +static void dm_test_default_clock_levels_engine(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + uint32_t expected[] = { 300000, 360000, 423530, 514290, 626090, 720000 }; + int i; + + get_default_clock_levels(DM_PP_CLOCK_TYPE_ENGINE_CLK, &clks); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 6U); + for (i = 0; i < 6; i++) + KUNIT_EXPECT_EQ(test, clks.clocks_in_khz[i], expected[i]); +} + +/** + * dm_test_default_clock_levels_memory - Test memory clock default levels + * @test: KUnit test context + * + * Verify that get_default_clock_levels populates 2 memory clock levels + * with the expected frequencies in kHz. + */ +static void dm_test_default_clock_levels_memory(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + + get_default_clock_levels(DM_PP_CLOCK_TYPE_MEMORY_CLK, &clks); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 2U); + KUNIT_EXPECT_EQ(test, clks.clocks_in_khz[0], 333000U); + KUNIT_EXPECT_EQ(test, clks.clocks_in_khz[1], 800000U); +} + +/** + * dm_test_default_clock_levels_unknown - Test unknown clock type default + * @test: KUnit test context + * + * Verify that get_default_clock_levels sets num_levels to 0 for an + * unrecognized clock type. + */ +static void dm_test_default_clock_levels_unknown(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + + get_default_clock_levels(DM_PP_CLOCK_TYPE_FCLK, &clks); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 0U); +} + +/* ---- Tests for dc_to_pp_clock_type ---- */ + +/** + * dm_test_dc_to_pp_clock_type_display - Test display clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_DISPLAY_CLK maps to amd_pp_disp_clock. + */ +static void dm_test_dc_to_pp_clock_type_display(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_DISPLAY_CLK), + (int)amd_pp_disp_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_engine - Test engine clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_ENGINE_CLK maps to amd_pp_sys_clock. + */ +static void dm_test_dc_to_pp_clock_type_engine(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_ENGINE_CLK), + (int)amd_pp_sys_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_memory - Test memory clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_MEMORY_CLK maps to amd_pp_mem_clock. + */ +static void dm_test_dc_to_pp_clock_type_memory(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_MEMORY_CLK), + (int)amd_pp_mem_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_dcefclk - Test DCEF clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_DCEFCLK maps to amd_pp_dcef_clock. + */ +static void dm_test_dc_to_pp_clock_type_dcefclk(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_DCEFCLK), + (int)amd_pp_dcef_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_dcfclk - Test DCF clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_DCFCLK maps to amd_pp_dcf_clock. + */ +static void dm_test_dc_to_pp_clock_type_dcfclk(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_DCFCLK), + (int)amd_pp_dcf_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_pixelclk - Test pixel clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_PIXELCLK maps to amd_pp_pixel_clock. + */ +static void dm_test_dc_to_pp_clock_type_pixelclk(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_PIXELCLK), + (int)amd_pp_pixel_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_fclk - Test FCLK type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_FCLK maps to amd_pp_f_clock. + */ +static void dm_test_dc_to_pp_clock_type_fclk(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_FCLK), + (int)amd_pp_f_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_phyclk - Test display PHY clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_DISPLAYPHYCLK maps to amd_pp_phy_clock. + */ +static void dm_test_dc_to_pp_clock_type_phyclk(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_DISPLAYPHYCLK), + (int)amd_pp_phy_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_dppclk - Test DPP clock type mapping + * @test: KUnit test context + * + * Verify DM_PP_CLOCK_TYPE_DPPCLK maps to amd_pp_dpp_clock. + */ +static void dm_test_dc_to_pp_clock_type_dppclk(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(DM_PP_CLOCK_TYPE_DPPCLK), + (int)amd_pp_dpp_clock); +} + +/** + * dm_test_dc_to_pp_clock_type_invalid - Test invalid clock type mapping + * @test: KUnit test context + * + * Verify that an invalid clock type value maps to 0. + */ +static void dm_test_dc_to_pp_clock_type_invalid(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, (int)dc_to_pp_clock_type(0), 0); +} + +/* ---- Tests for pp_to_dc_clock_levels ---- */ + +/** + * dm_test_pp_to_dc_clock_levels_within_limit - Test normal copy within limit + * @test: KUnit test context + * + * Verify that pp_to_dc_clock_levels correctly copies clock values when the + * count is within DM_PP_MAX_CLOCK_LEVELS. + */ +static void dm_test_pp_to_dc_clock_levels_within_limit(struct kunit *test) +{ + struct amd_pp_clocks pp_clks = {}; + struct dm_pp_clock_levels dc_clks = {}; + + pp_clks.count = 3; + pp_clks.clock[0] = 300000; + pp_clks.clock[1] = 500000; + pp_clks.clock[2] = 700000; + + pp_to_dc_clock_levels(&pp_clks, &dc_clks, DM_PP_CLOCK_TYPE_ENGINE_CLK); + + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, 3U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[0], 300000U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[1], 500000U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[2], 700000U); +} + +/** + * dm_test_pp_to_dc_clock_levels_caps_at_max - Test count capping at max + * @test: KUnit test context + * + * Verify that pp_to_dc_clock_levels caps num_levels at DM_PP_MAX_CLOCK_LEVELS + * when the input count exceeds the maximum. + */ +static void dm_test_pp_to_dc_clock_levels_caps_at_max(struct kunit *test) +{ + struct amd_pp_clocks pp_clks = {}; + struct dm_pp_clock_levels dc_clks = {}; + uint32_t i; + + pp_clks.count = DM_PP_MAX_CLOCK_LEVELS + 1; + for (i = 0; i < DM_PP_MAX_CLOCK_LEVELS; i++) + pp_clks.clock[i] = (i + 1) * 100000; + + pp_to_dc_clock_levels(&pp_clks, &dc_clks, DM_PP_CLOCK_TYPE_ENGINE_CLK); + + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, (uint32_t)DM_PP_MAX_CLOCK_LEVELS); +} + +/* ---- Tests for pp_to_dc_clock_levels_with_latency ---- */ + +/** + * dm_test_pp_to_dc_clock_levels_latency_within_limit - Test normal copy + * @test: KUnit test context + * + * Verify that pp_to_dc_clock_levels_with_latency correctly copies clock + * and latency values when count is within limits. + */ +static void dm_test_pp_to_dc_clock_levels_latency_within_limit(struct kunit *test) +{ + struct pp_clock_levels_with_latency pp_clks = {}; + struct dm_pp_clock_levels_with_latency dc_clks = {}; + + pp_clks.num_levels = 2; + pp_clks.data[0].clocks_in_khz = 400000; + pp_clks.data[0].latency_in_us = 10; + pp_clks.data[1].clocks_in_khz = 800000; + pp_clks.data[1].latency_in_us = 20; + + pp_to_dc_clock_levels_with_latency(&pp_clks, &dc_clks, + DM_PP_CLOCK_TYPE_ENGINE_CLK); + + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, 2U); + KUNIT_EXPECT_EQ(test, dc_clks.data[0].clocks_in_khz, 400000U); + KUNIT_EXPECT_EQ(test, dc_clks.data[0].latency_in_us, 10U); + KUNIT_EXPECT_EQ(test, dc_clks.data[1].clocks_in_khz, 800000U); + KUNIT_EXPECT_EQ(test, dc_clks.data[1].latency_in_us, 20U); +} + +/** + * dm_test_pp_to_dc_clock_levels_latency_caps_at_max - Test count capping + * @test: KUnit test context + * + * Verify that pp_to_dc_clock_levels_with_latency caps num_levels at + * DM_PP_MAX_CLOCK_LEVELS when input exceeds the maximum. + */ +static void dm_test_pp_to_dc_clock_levels_latency_caps_at_max(struct kunit *test) +{ + struct pp_clock_levels_with_latency pp_clks = {}; + struct dm_pp_clock_levels_with_latency dc_clks = {}; + + pp_clks.num_levels = DM_PP_MAX_CLOCK_LEVELS + 1; + + pp_to_dc_clock_levels_with_latency(&pp_clks, &dc_clks, + DM_PP_CLOCK_TYPE_ENGINE_CLK); + + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, (uint32_t)DM_PP_MAX_CLOCK_LEVELS); +} + +/* ---- Tests for pp_to_dc_clock_levels_with_voltage ---- */ + +/** + * dm_test_pp_to_dc_clock_levels_voltage_within_limit - Test normal copy + * @test: KUnit test context + * + * Verify that pp_to_dc_clock_levels_with_voltage correctly copies clock + * and voltage values when count is within limits. + */ +static void dm_test_pp_to_dc_clock_levels_voltage_within_limit(struct kunit *test) +{ + struct pp_clock_levels_with_voltage pp_clks = {}; + struct dm_pp_clock_levels_with_voltage dc_clks = {}; + + pp_clks.num_levels = 2; + pp_clks.data[0].clocks_in_khz = 300000; + pp_clks.data[0].voltage_in_mv = 800; + pp_clks.data[1].clocks_in_khz = 600000; + pp_clks.data[1].voltage_in_mv = 950; + + pp_to_dc_clock_levels_with_voltage(&pp_clks, &dc_clks, + DM_PP_CLOCK_TYPE_MEMORY_CLK); + + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, 2U); + KUNIT_EXPECT_EQ(test, dc_clks.data[0].clocks_in_khz, 300000U); + KUNIT_EXPECT_EQ(test, dc_clks.data[0].voltage_in_mv, 800U); + KUNIT_EXPECT_EQ(test, dc_clks.data[1].clocks_in_khz, 600000U); + KUNIT_EXPECT_EQ(test, dc_clks.data[1].voltage_in_mv, 950U); +} + +/** + * dm_test_pp_to_dc_clock_levels_voltage_caps_at_max - Test count capping + * @test: KUnit test context + * + * Verify that pp_to_dc_clock_levels_with_voltage caps num_levels at + * DM_PP_MAX_CLOCK_LEVELS when input exceeds the maximum. + */ +static void dm_test_pp_to_dc_clock_levels_voltage_caps_at_max(struct kunit *test) +{ + struct pp_clock_levels_with_voltage pp_clks = {}; + struct dm_pp_clock_levels_with_voltage dc_clks = {}; + + pp_clks.num_levels = DM_PP_MAX_CLOCK_LEVELS + 1; + + pp_to_dc_clock_levels_with_voltage(&pp_clks, &dc_clks, + DM_PP_CLOCK_TYPE_MEMORY_CLK); + + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, (uint32_t)DM_PP_MAX_CLOCK_LEVELS); +} + +/* ---- Tests for dm_pp_get_funcs ---- */ + +/** + * dm_test_get_funcs_rv - Test Raven PP SMU function table setup + * @test: KUnit test context + * + * Verify that DCN 1.0 initializes the Raven SMU function table and stores + * the DC context in the PP SMU handle. + */ +static void dm_test_get_funcs_rv(struct kunit *test) +{ + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu_funcs *funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, funcs); + + ctx->dce_version = DCN_VERSION_1_0; + + dm_pp_get_funcs(ctx, funcs); + + KUNIT_EXPECT_EQ(test, funcs->ctx.ver, PP_SMU_VER_RV); + KUNIT_EXPECT_PTR_EQ(test, funcs->rv_funcs.pp_smu.dm, ctx); + KUNIT_EXPECT_TRUE(test, funcs->rv_funcs.set_wm_ranges != NULL); + KUNIT_EXPECT_TRUE(test, funcs->rv_funcs.set_pme_wa_enable != NULL); + KUNIT_EXPECT_TRUE(test, funcs->rv_funcs.set_display_count != NULL); + KUNIT_EXPECT_TRUE(test, funcs->rv_funcs.set_min_deep_sleep_dcfclk != NULL); + KUNIT_EXPECT_TRUE(test, funcs->rv_funcs.set_hard_min_dcfclk_by_freq != NULL); + KUNIT_EXPECT_TRUE(test, funcs->rv_funcs.set_hard_min_fclk_by_freq != NULL); + KUNIT_EXPECT_FALSE(test, funcs->rv_funcs.set_hard_min_socclk_by_freq != NULL); +} + +/** + * dm_test_get_funcs_rv_101 - Test DCN 1.01 Raven PP SMU setup + * @test: KUnit test context + * + * Verify that DCN 1.01 uses the same Raven SMU function table as DCN 1.0. + */ +static void dm_test_get_funcs_rv_101(struct kunit *test) +{ + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu_funcs *funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, funcs); + + ctx->dce_version = DCN_VERSION_1_01; + + dm_pp_get_funcs(ctx, funcs); + + KUNIT_EXPECT_EQ(test, funcs->ctx.ver, PP_SMU_VER_RV); + KUNIT_EXPECT_PTR_EQ(test, funcs->rv_funcs.pp_smu.dm, ctx); + KUNIT_EXPECT_TRUE(test, funcs->rv_funcs.set_display_count != NULL); +} + +/** + * dm_test_get_funcs_nv - Test Navi PP SMU function table setup + * @test: KUnit test context + * + * Verify that DCN 2.0 initializes the Navi SMU function table and leaves the + * unsupported PME workaround callback unset. + */ +static void dm_test_get_funcs_nv(struct kunit *test) +{ + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu_funcs *funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, funcs); + + ctx->dce_version = DCN_VERSION_2_0; + + dm_pp_get_funcs(ctx, funcs); + + KUNIT_EXPECT_EQ(test, funcs->ctx.ver, PP_SMU_VER_NV); + KUNIT_EXPECT_PTR_EQ(test, funcs->nv_funcs.pp_smu.dm, ctx); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.set_display_count != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.set_hard_min_dcfclk_by_freq != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.set_min_deep_sleep_dcfclk != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.set_voltage_by_freq != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.set_wm_ranges != NULL); + KUNIT_EXPECT_FALSE(test, funcs->nv_funcs.set_pme_wa_enable != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.set_hard_min_uclk_by_freq != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.get_maximum_sustainable_clocks != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.get_uclk_dpm_states != NULL); + KUNIT_EXPECT_TRUE(test, funcs->nv_funcs.set_pstate_handshake_support != NULL); +} + +/** + * dm_test_get_funcs_rn - Test Renoir PP SMU function table setup + * @test: KUnit test context + * + * Verify that DCN 2.1 initializes the Renoir SMU function table. + */ +static void dm_test_get_funcs_rn(struct kunit *test) +{ + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu_funcs *funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, funcs); + + ctx->dce_version = DCN_VERSION_2_1; + + dm_pp_get_funcs(ctx, funcs); + + KUNIT_EXPECT_EQ(test, funcs->ctx.ver, PP_SMU_VER_RN); + KUNIT_EXPECT_PTR_EQ(test, funcs->rn_funcs.pp_smu.dm, ctx); + KUNIT_EXPECT_TRUE(test, funcs->rn_funcs.set_wm_ranges != NULL); + KUNIT_EXPECT_TRUE(test, funcs->rn_funcs.get_dpm_clock_table != NULL); +} + +/** + * dm_test_get_funcs_unsupported - Test unsupported DCE version handling + * @test: KUnit test context + * + * Verify that unsupported DCE versions do not initialize a PP SMU version or + * function table callbacks. + */ +static void dm_test_get_funcs_unsupported(struct kunit *test) +{ + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu_funcs *funcs = kunit_kzalloc(test, sizeof(*funcs), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, ctx); + KUNIT_ASSERT_NOT_NULL(test, funcs); + + ctx->dce_version = DCE_VERSION_MAX; + + dm_pp_get_funcs(ctx, funcs); + + KUNIT_EXPECT_EQ(test, funcs->ctx.ver, PP_SMU_UNSUPPORTED); + KUNIT_EXPECT_FALSE(test, funcs->rv_funcs.set_wm_ranges != NULL); +} + +/* ---- Tests for amdgpu_device-backed entry points ---- */ + +/** + * dm_test_apply_display_requirements_dpm_disabled - Test DPM-disabled path + * @test: KUnit test context + * + * Verify that dm_pp_apply_display_requirements returns true without touching + * the display configuration when DPM is disabled. + */ +static void dm_test_apply_display_requirements_dpm_disabled(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_display_configuration cfg = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + adev->pm.dpm_enabled = false; + ctx->driver_context = adev; + + KUNIT_EXPECT_TRUE(test, dm_pp_apply_display_requirements(ctx, &cfg)); +} + +/** + * dm_test_apply_clock_for_voltage_invalid_type - Test invalid clock type path + * @test: KUnit test context + * + * Verify that dm_pp_apply_clock_for_voltage_request returns false for a clock + * type that does not map to a valid PP clock type, taking the early-return + * path before any SMU request is issued. + */ +static void dm_test_apply_clock_for_voltage_invalid_type(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_for_voltage_req req = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + ctx->driver_context = adev; + req.clk_type = (enum dm_pp_clock_type)0xffff; + req.clocks_in_khz = 500000; + + KUNIT_EXPECT_FALSE(test, dm_pp_apply_clock_for_voltage_request(ctx, &req)); +} + +/* ---- Tests for build_pm_display_cfg ---- */ + +/** + * dm_test_build_pm_display_cfg_scalar_fields - Test scalar field translation + * @test: KUnit test context + * + * Verify that build_pm_display_cfg copies the pass-through fields and applies + * the /10 (10 kHz) scaling, and sets the fixed constants. + */ +static void dm_test_build_pm_display_cfg_scalar_fields(struct kunit *test) +{ + struct amd_pp_display_configuration *pm = + kunit_kzalloc(test, sizeof(*pm), GFP_KERNEL); + struct dm_pp_display_configuration *pp = + kunit_kzalloc(test, sizeof(*pp), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, pm); + KUNIT_ASSERT_NOT_NULL(test, pp); + + pp->cpu_cc6_disable = true; + pp->cpu_pstate_disable = true; + pp->cpu_pstate_separation_time = 7; + pp->nb_pstate_switch_disable = true; + pp->display_count = 2; + pp->min_engine_clock_khz = 300000; + pp->min_engine_clock_deep_sleep_khz = 50000; + pp->min_memory_clock_khz = 800000; + pp->min_dcfclock_khz = 600000; + pp->all_displays_in_sync = true; + pp->avail_mclk_switch_time_us = 11; + pp->disp_clk_khz = 400000; + pp->avail_mclk_switch_time_in_disp_active_us = 13; + pp->crtc_index = 3; + pp->line_time_in_us = 17; + pp->disp_configs[0].v_refresh = 60; + + build_pm_display_cfg(pm, pp); + + KUNIT_EXPECT_TRUE(test, pm->cpu_cc6_disable); + KUNIT_EXPECT_TRUE(test, pm->cpu_pstate_disable); + KUNIT_EXPECT_EQ(test, pm->cpu_pstate_separation_time, 7); + KUNIT_EXPECT_TRUE(test, pm->nb_pstate_switch_disable); + KUNIT_EXPECT_EQ(test, pm->num_display, 2); + KUNIT_EXPECT_EQ(test, pm->num_path_including_non_display, 2); + KUNIT_EXPECT_EQ(test, pm->min_core_set_clock, 30000); + KUNIT_EXPECT_EQ(test, pm->min_core_set_clock_in_sr, 5000); + KUNIT_EXPECT_EQ(test, pm->min_mem_set_clock, 80000); + KUNIT_EXPECT_EQ(test, pm->min_dcef_deep_sleep_set_clk, 5000); + KUNIT_EXPECT_EQ(test, pm->min_dcef_set_clk, 60000); + KUNIT_EXPECT_TRUE(test, pm->multi_monitor_in_sync); + KUNIT_EXPECT_EQ(test, pm->min_vblank_time, 11); + KUNIT_EXPECT_EQ(test, pm->display_clk, 40000); + KUNIT_EXPECT_EQ(test, pm->dce_tolerable_mclk_in_active_latency, 13); + KUNIT_EXPECT_EQ(test, pm->crtc_index, 3); + KUNIT_EXPECT_EQ(test, pm->line_time_in_us, 17); + KUNIT_EXPECT_EQ(test, pm->vrefresh, 60); + KUNIT_EXPECT_EQ(test, pm->crossfire_display_index, -1); + KUNIT_EXPECT_EQ(test, pm->min_bus_bandwidth, 0); +} + +/** + * dm_test_build_pm_display_cfg_per_display - Test per-display translation + * @test: KUnit test context + * + * Verify that build_pm_display_cfg maps each display config, applying the + * controller_id = pipe_idx + 1 offset and copying the pixel clock. + */ +static void dm_test_build_pm_display_cfg_per_display(struct kunit *test) +{ + struct amd_pp_display_configuration *pm = + kunit_kzalloc(test, sizeof(*pm), GFP_KERNEL); + struct dm_pp_display_configuration *pp = + kunit_kzalloc(test, sizeof(*pp), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, pm); + KUNIT_ASSERT_NOT_NULL(test, pp); + + pp->display_count = 2; + pp->disp_configs[0].pipe_idx = 0; + pp->disp_configs[0].pixel_clock = 148500; + pp->disp_configs[1].pipe_idx = 4; + pp->disp_configs[1].pixel_clock = 297000; + + build_pm_display_cfg(pm, pp); + + KUNIT_EXPECT_EQ(test, pm->displays[0].controller_id, 1); + KUNIT_EXPECT_EQ(test, pm->displays[0].pixel_clock, 148500); + KUNIT_EXPECT_EQ(test, pm->displays[1].controller_id, 5); + KUNIT_EXPECT_EQ(test, pm->displays[1].pixel_clock, 297000); +} + +/* ---- Tests for build_wm_clock_ranges_soc15 ---- */ + +/** + * dm_test_build_wm_clock_ranges_dmif - Test reader (DMIF) watermark sets + * @test: KUnit test context + * + * Verify that build_wm_clock_ranges_soc15 copies the reader set count, + * maps wm_inst to wm_set_id (clamping instances > 3 to WM_SET_A), and + * converts every clock from MHz to kHz (x1000) into the DMIF clock ranges. + */ +static void dm_test_build_wm_clock_ranges_dmif(struct kunit *test) +{ + struct pp_smu_wm_range_sets *ranges = + kunit_kzalloc(test, sizeof(*ranges), GFP_KERNEL); + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm = + kunit_kzalloc(test, sizeof(*wm), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, ranges); + KUNIT_ASSERT_NOT_NULL(test, wm); + + ranges->num_reader_wm_sets = 2; + /* set 0: wm_inst within range -> preserved */ + ranges->reader_wm_sets[0].wm_inst = 2; + ranges->reader_wm_sets[0].max_drain_clk_mhz = 600; + ranges->reader_wm_sets[0].min_drain_clk_mhz = 300; + ranges->reader_wm_sets[0].max_fill_clk_mhz = 800; + ranges->reader_wm_sets[0].min_fill_clk_mhz = 400; + /* set 1: wm_inst > 3 -> clamped to WM_SET_A */ + ranges->reader_wm_sets[1].wm_inst = 5; + ranges->reader_wm_sets[1].max_drain_clk_mhz = 700; + ranges->reader_wm_sets[1].min_drain_clk_mhz = 350; + ranges->reader_wm_sets[1].max_fill_clk_mhz = 900; + ranges->reader_wm_sets[1].min_fill_clk_mhz = 450; + + build_wm_clock_ranges_soc15(ranges, wm); + + KUNIT_EXPECT_EQ(test, wm->num_wm_dmif_sets, 2U); + KUNIT_EXPECT_EQ(test, wm->num_wm_mcif_sets, 0U); + + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[0].wm_set_id, WM_SET_C); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[0].wm_max_dcfclk_clk_in_khz, 600000U); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[0].wm_min_dcfclk_clk_in_khz, 300000U); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[0].wm_max_mem_clk_in_khz, 800000U); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[0].wm_min_mem_clk_in_khz, 400000U); + + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[1].wm_set_id, WM_SET_A); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[1].wm_max_dcfclk_clk_in_khz, 700000U); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[1].wm_min_dcfclk_clk_in_khz, 350000U); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[1].wm_max_mem_clk_in_khz, 900000U); + KUNIT_EXPECT_EQ(test, wm->wm_dmif_clocks_ranges[1].wm_min_mem_clk_in_khz, 450000U); +} + +/** + * dm_test_build_wm_clock_ranges_mcif - Test writer (MCIF) watermark sets + * @test: KUnit test context + * + * Verify that build_wm_clock_ranges_soc15 copies the writer set count and + * maps the writer clocks into the MCIF ranges: fill clocks become socclk + * and drain clocks become mem clk, each converted from MHz to kHz. + */ +static void dm_test_build_wm_clock_ranges_mcif(struct kunit *test) +{ + struct pp_smu_wm_range_sets *ranges = + kunit_kzalloc(test, sizeof(*ranges), GFP_KERNEL); + struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm = + kunit_kzalloc(test, sizeof(*wm), GFP_KERNEL); + + KUNIT_ASSERT_NOT_NULL(test, ranges); + KUNIT_ASSERT_NOT_NULL(test, wm); + + ranges->num_writer_wm_sets = 2; + ranges->writer_wm_sets[0].wm_inst = 1; + ranges->writer_wm_sets[0].max_fill_clk_mhz = 1200; + ranges->writer_wm_sets[0].min_fill_clk_mhz = 600; + ranges->writer_wm_sets[0].max_drain_clk_mhz = 1000; + ranges->writer_wm_sets[0].min_drain_clk_mhz = 500; + /* set 1: wm_inst > 3 -> clamped to WM_SET_A */ + ranges->writer_wm_sets[1].wm_inst = 5; + ranges->writer_wm_sets[1].max_fill_clk_mhz = 1400; + ranges->writer_wm_sets[1].min_fill_clk_mhz = 700; + ranges->writer_wm_sets[1].max_drain_clk_mhz = 1100; + ranges->writer_wm_sets[1].min_drain_clk_mhz = 550; + + build_wm_clock_ranges_soc15(ranges, wm); + + KUNIT_EXPECT_EQ(test, wm->num_wm_dmif_sets, 0U); + KUNIT_EXPECT_EQ(test, wm->num_wm_mcif_sets, 2U); + + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[0].wm_set_id, WM_SET_B); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[0].wm_max_socclk_clk_in_khz, 1200000U); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[0].wm_min_socclk_clk_in_khz, 600000U); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[0].wm_max_mem_clk_in_khz, 1000000U); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[0].wm_min_mem_clk_in_khz, 500000U); + + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[1].wm_set_id, WM_SET_A); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[1].wm_max_socclk_clk_in_khz, 1400000U); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[1].wm_min_socclk_clk_in_khz, 700000U); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[1].wm_max_mem_clk_in_khz, 1100000U); + KUNIT_EXPECT_EQ(test, wm->wm_mcif_clocks_ranges[1].wm_min_mem_clk_in_khz, 550000U); +} + +/* ---- Tests for cap_clock_levels_to_validation ---- */ + +/** + * dm_test_cap_clock_levels_engine_caps - Test engine clock level capping + * @test: KUnit test context + * + * Verify that for engine clocks, num_levels is reduced to the index of the + * first level whose frequency exceeds the engine validation clock. + */ +static void dm_test_cap_clock_levels_engine_caps(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + struct amd_pp_simple_clock_info validation = { + .engine_max_clock = 450000, + .memory_max_clock = 800000, + }; + + clks.num_levels = 3; + clks.clocks_in_khz[0] = 300000; + clks.clocks_in_khz[1] = 400000; + clks.clocks_in_khz[2] = 500000; + + cap_clock_levels_to_validation(&clks, DM_PP_CLOCK_TYPE_ENGINE_CLK, &validation); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 2U); +} + +/** + * dm_test_cap_clock_levels_engine_first_exceeds - Test floor of one level + * @test: KUnit test context + * + * Verify that when the very first engine clock level already exceeds the + * validation clock, num_levels is clamped to 1 rather than 0. + */ +static void dm_test_cap_clock_levels_engine_first_exceeds(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + struct amd_pp_simple_clock_info validation = { + .engine_max_clock = 100000, + .memory_max_clock = 800000, + }; + + clks.num_levels = 3; + clks.clocks_in_khz[0] = 300000; + clks.clocks_in_khz[1] = 400000; + clks.clocks_in_khz[2] = 500000; + + cap_clock_levels_to_validation(&clks, DM_PP_CLOCK_TYPE_ENGINE_CLK, &validation); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 1U); +} + +/** + * dm_test_cap_clock_levels_memory_caps - Test memory clock level capping + * @test: KUnit test context + * + * Verify that for memory clocks, num_levels is reduced based on the memory + * validation clock (and is unaffected by the engine validation clock). + */ +static void dm_test_cap_clock_levels_memory_caps(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + struct amd_pp_simple_clock_info validation = { + .engine_max_clock = 100000, + .memory_max_clock = 700000, + }; + + clks.num_levels = 2; + clks.clocks_in_khz[0] = 333000; + clks.clocks_in_khz[1] = 800000; + + cap_clock_levels_to_validation(&clks, DM_PP_CLOCK_TYPE_MEMORY_CLK, &validation); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 1U); +} + +/** + * dm_test_cap_clock_levels_within_limit - Test no capping when within limit + * @test: KUnit test context + * + * Verify that num_levels is left unchanged when no level exceeds the + * validation clock. + */ +static void dm_test_cap_clock_levels_within_limit(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + struct amd_pp_simple_clock_info validation = { + .engine_max_clock = 999000, + .memory_max_clock = 999000, + }; + + clks.num_levels = 3; + clks.clocks_in_khz[0] = 300000; + clks.clocks_in_khz[1] = 400000; + clks.clocks_in_khz[2] = 500000; + + cap_clock_levels_to_validation(&clks, DM_PP_CLOCK_TYPE_ENGINE_CLK, &validation); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 3U); +} + +/** + * dm_test_cap_clock_levels_other_type - Test non-engine/memory types ignored + * @test: KUnit test context + * + * Verify that for clock types other than engine or memory, num_levels is + * left unchanged regardless of the validation clocks. + */ +static void dm_test_cap_clock_levels_other_type(struct kunit *test) +{ + struct dm_pp_clock_levels clks = { 0 }; + struct amd_pp_simple_clock_info validation = { + .engine_max_clock = 1, + .memory_max_clock = 1, + }; + + clks.num_levels = 3; + clks.clocks_in_khz[0] = 300000; + clks.clocks_in_khz[1] = 400000; + clks.clocks_in_khz[2] = 500000; + + cap_clock_levels_to_validation(&clks, DM_PP_CLOCK_TYPE_DISPLAY_CLK, &validation); + + KUNIT_EXPECT_EQ(test, clks.num_levels, 3U); +} + +/* ---- Tests for pp_smu_nv_clock_id_to_pp ---- */ + +/** + * dm_test_nv_clock_id_dispclk - Test DISPCLK id mapping + * @test: KUnit test context + * + * Verify that PP_SMU_NV_DISPCLK maps to amd_pp_disp_clock and returns true. + */ +static void dm_test_nv_clock_id_dispclk(struct kunit *test) +{ + enum amd_pp_clock_type clock_type = amd_pp_mem_clock; + + KUNIT_EXPECT_TRUE(test, pp_smu_nv_clock_id_to_pp(PP_SMU_NV_DISPCLK, &clock_type)); + KUNIT_EXPECT_EQ(test, clock_type, amd_pp_disp_clock); +} + +/** + * dm_test_nv_clock_id_phyclk - Test PHYCLK id mapping + * @test: KUnit test context + * + * Verify that PP_SMU_NV_PHYCLK maps to amd_pp_phy_clock and returns true. + */ +static void dm_test_nv_clock_id_phyclk(struct kunit *test) +{ + enum amd_pp_clock_type clock_type = amd_pp_mem_clock; + + KUNIT_EXPECT_TRUE(test, pp_smu_nv_clock_id_to_pp(PP_SMU_NV_PHYCLK, &clock_type)); + KUNIT_EXPECT_EQ(test, clock_type, amd_pp_phy_clock); +} + +/** + * dm_test_nv_clock_id_pixelclk - Test PIXELCLK id mapping + * @test: KUnit test context + * + * Verify that PP_SMU_NV_PIXELCLK maps to amd_pp_pixel_clock and returns true. + */ +static void dm_test_nv_clock_id_pixelclk(struct kunit *test) +{ + enum amd_pp_clock_type clock_type = amd_pp_mem_clock; + + KUNIT_EXPECT_TRUE(test, pp_smu_nv_clock_id_to_pp(PP_SMU_NV_PIXELCLK, &clock_type)); + KUNIT_EXPECT_EQ(test, clock_type, amd_pp_pixel_clock); +} + +/** + * dm_test_nv_clock_id_invalid - Test unknown id is rejected + * @test: KUnit test context + * + * Verify that an unknown clock id returns false and leaves the output + * clock_type untouched, guarding against the previously uninitialized path. + */ +static void dm_test_nv_clock_id_invalid(struct kunit *test) +{ + enum amd_pp_clock_type clock_type = amd_pp_dcef_clock; + + KUNIT_EXPECT_FALSE(test, pp_smu_nv_clock_id_to_pp((enum pp_smu_nv_clock_id)0xff, + &clock_type)); + KUNIT_EXPECT_EQ(test, clock_type, amd_pp_dcef_clock); +} + +/* ---- Tests using stub DPM layer ---- */ + +/** + * dm_test_apply_display_requirements_dpm_enabled - Test DPM-enabled path + * @test: KUnit test context + * + * Verify that dm_pp_apply_display_requirements calls build_pm_display_cfg + * and the DPM callbacks when DPM is enabled, and returns true. + */ +static void dm_test_apply_display_requirements_dpm_enabled(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_display_configuration cfg = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + adev->pm.dpm_enabled = true; + + cfg.display_count = 1; + cfg.min_engine_clock_khz = 300000; + cfg.disp_configs[0].v_refresh = 60; + + KUNIT_EXPECT_TRUE(test, dm_pp_apply_display_requirements(ctx, &cfg)); + KUNIT_EXPECT_EQ(test, adev->pm.pm_display_cfg.min_core_set_clock, 30000); + KUNIT_EXPECT_EQ(test, adev->pm.pm_display_cfg.vrefresh, 60); +} + +/** + * dm_test_get_clock_levels_by_type_dpm_error - Test DPM error fallback + * @test: KUnit test context + * + * Verify that dm_pp_get_clock_levels_by_type falls back to default clock + * levels when amdgpu_dpm_get_clock_by_type returns an error. + */ +static void dm_test_get_clock_levels_by_type_dpm_error(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_levels dc_clks = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + stub_dpm_ctx->ret_val = -EINVAL; + + KUNIT_EXPECT_TRUE(test, dm_pp_get_clock_levels_by_type(ctx, + DM_PP_CLOCK_TYPE_DISPLAY_CLK, &dc_clks)); + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, 6U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[0], 300000U); +} + +/** + * dm_test_get_clock_levels_by_type_success - Test successful clock query + * @test: KUnit test context + * + * Verify that dm_pp_get_clock_levels_by_type returns the queried clocks + * capped by validation clocks. + */ +static void dm_test_get_clock_levels_by_type_success(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_levels dc_clks = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + + stub_dpm_ctx->get_clock_by_type_clocks.count = 3; + stub_dpm_ctx->get_clock_by_type_clocks.clock[0] = 300000; + stub_dpm_ctx->get_clock_by_type_clocks.clock[1] = 500000; + stub_dpm_ctx->get_clock_by_type_clocks.clock[2] = 700000; + + /* validation at 60000 * 10 = 600000 kHz → caps to 2 levels */ + stub_dpm_ctx->get_validation_clks.engine_max_clock = 60000; + stub_dpm_ctx->get_validation_clks.memory_max_clock = 80000; + + KUNIT_EXPECT_TRUE(test, dm_pp_get_clock_levels_by_type(ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, &dc_clks)); + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, 2U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[0], 300000U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[1], 500000U); +} + +/** + * dm_test_get_clock_levels_by_type_validation_fallback - Test validation error + * @test: KUnit test context + * + * Verify that dm_pp_get_clock_levels_by_type uses default validation clocks + * (engine=720000, memory=800000 kHz) when get_display_mode_validation_clocks + * returns an error, capping levels accordingly. + */ +static void dm_test_get_clock_levels_by_type_validation_fallback(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_levels dc_clks = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + + /* get_clock_by_type succeeds with 3 engine clock levels */ + stub_dpm_ctx->get_clock_by_type_clocks.count = 3; + stub_dpm_ctx->get_clock_by_type_clocks.clock[0] = 300000; + stub_dpm_ctx->get_clock_by_type_clocks.clock[1] = 500000; + stub_dpm_ctx->get_clock_by_type_clocks.clock[2] = 800000; + + /* Force validation clocks to fail → triggers default path */ + stub_dpm_ctx->get_validation_clks_ret = -EINVAL; + + KUNIT_EXPECT_TRUE(test, dm_pp_get_clock_levels_by_type(ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, &dc_clks)); + /* + * Default validation: engine_max_clock = 72000 * 10 = 720000 kHz. + * Clocks 300000 and 500000 are within limit, 800000 exceeds it, + * so num_levels is capped to 2. + */ + KUNIT_EXPECT_EQ(test, dc_clks.num_levels, 2U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[0], 300000U); + KUNIT_EXPECT_EQ(test, dc_clks.clocks_in_khz[1], 500000U); +} + +/** + * dm_test_get_clock_levels_with_latency_success - Test latency clock query + * @test: KUnit test context + * + * Verify dm_pp_get_clock_levels_by_type_with_latency returns true and + * copies the clock/latency data from the DPM backend. + */ +static void dm_test_get_clock_levels_with_latency_success(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_levels_with_latency info = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + + stub_dpm_ctx->get_clock_by_type_with_latency_clks.num_levels = 1; + stub_dpm_ctx->get_clock_by_type_with_latency_clks.data[0].clocks_in_khz = 600000; + stub_dpm_ctx->get_clock_by_type_with_latency_clks.data[0].latency_in_us = 15; + + KUNIT_EXPECT_TRUE(test, dm_pp_get_clock_levels_by_type_with_latency(ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, &info)); + KUNIT_EXPECT_EQ(test, info.num_levels, 1U); + KUNIT_EXPECT_EQ(test, info.data[0].clocks_in_khz, 600000U); + KUNIT_EXPECT_EQ(test, info.data[0].latency_in_us, 15U); +} + +/** + * dm_test_get_clock_levels_with_latency_failure - Test latency query error + * @test: KUnit test context + * + * Verify dm_pp_get_clock_levels_by_type_with_latency returns false on DPM error. + */ +static void dm_test_get_clock_levels_with_latency_failure(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_levels_with_latency info = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + stub_dpm_ctx->ret_val = -EINVAL; + + KUNIT_EXPECT_FALSE(test, dm_pp_get_clock_levels_by_type_with_latency(ctx, + DM_PP_CLOCK_TYPE_ENGINE_CLK, &info)); +} + +/** + * dm_test_get_clock_levels_with_voltage_success - Test voltage clock query + * @test: KUnit test context + * + * Verify dm_pp_get_clock_levels_by_type_with_voltage returns true and + * copies the clock/voltage data from the DPM backend. + */ +static void dm_test_get_clock_levels_with_voltage_success(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_levels_with_voltage info = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + + stub_dpm_ctx->get_clock_by_type_with_voltage_clks.num_levels = 1; + stub_dpm_ctx->get_clock_by_type_with_voltage_clks.data[0].clocks_in_khz = 400000; + stub_dpm_ctx->get_clock_by_type_with_voltage_clks.data[0].voltage_in_mv = 900; + + KUNIT_EXPECT_TRUE(test, dm_pp_get_clock_levels_by_type_with_voltage(ctx, + DM_PP_CLOCK_TYPE_MEMORY_CLK, &info)); + KUNIT_EXPECT_EQ(test, info.num_levels, 1U); + KUNIT_EXPECT_EQ(test, info.data[0].clocks_in_khz, 400000U); + KUNIT_EXPECT_EQ(test, info.data[0].voltage_in_mv, 900U); +} + +/** + * dm_test_get_clock_levels_with_voltage_failure - Test voltage query error + * @test: KUnit test context + * + * Verify dm_pp_get_clock_levels_by_type_with_voltage returns false on DPM error. + */ +static void dm_test_get_clock_levels_with_voltage_failure(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_levels_with_voltage info = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + stub_dpm_ctx->ret_val = -EINVAL; + + KUNIT_EXPECT_FALSE(test, dm_pp_get_clock_levels_by_type_with_voltage(ctx, + DM_PP_CLOCK_TYPE_MEMORY_CLK, &info)); +} + +/** + * dm_test_notify_wm_clock_changes_polaris - Test Polaris watermark path + * @test: KUnit test context + * + * Verify dm_pp_notify_wm_clock_changes returns true for Polaris ASICs + * when the DPM set_watermarks call succeeds. + */ +static void dm_test_notify_wm_clock_changes_polaris(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_wm_sets_with_clock_ranges wm = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + adev->asic_type = CHIP_POLARIS10; + stub_dpm_ctx->set_watermarks_ret = 0; + + KUNIT_EXPECT_TRUE(test, dm_pp_notify_wm_clock_changes(ctx, &wm)); +} + +/** + * dm_test_notify_wm_clock_changes_non_polaris - Test non-Polaris path + * @test: KUnit test context + * + * Verify dm_pp_notify_wm_clock_changes returns false for non-Polaris ASICs. + */ +static void dm_test_notify_wm_clock_changes_non_polaris(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_wm_sets_with_clock_ranges wm = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + adev->asic_type = CHIP_NAVI10; + + KUNIT_EXPECT_FALSE(test, dm_pp_notify_wm_clock_changes(ctx, &wm)); +} + +/** + * dm_test_apply_clock_for_voltage_success - Test successful voltage request + * @test: KUnit test context + * + * Verify dm_pp_apply_clock_for_voltage_request returns true when the DPM + * callback succeeds for a valid clock type. + */ +static void dm_test_apply_clock_for_voltage_success(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_for_voltage_req req = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + stub_dpm_ctx->display_clock_voltage_ret = 0; + + req.clk_type = DM_PP_CLOCK_TYPE_ENGINE_CLK; + req.clocks_in_khz = 500000; + + KUNIT_EXPECT_TRUE(test, dm_pp_apply_clock_for_voltage_request(ctx, &req)); +} + +/** + * dm_test_apply_clock_for_voltage_eopnotsupp - Test EOPNOTSUPP treated as success + * @test: KUnit test context + * + * Verify dm_pp_apply_clock_for_voltage_request returns true when the DPM + * callback returns -EOPNOTSUPP (not supported is non-fatal). + */ +static void dm_test_apply_clock_for_voltage_eopnotsupp(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_for_voltage_req req = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + stub_dpm_ctx->display_clock_voltage_ret = -EOPNOTSUPP; + + req.clk_type = DM_PP_CLOCK_TYPE_ENGINE_CLK; + req.clocks_in_khz = 500000; + + KUNIT_EXPECT_TRUE(test, dm_pp_apply_clock_for_voltage_request(ctx, &req)); +} + +/** + * dm_test_apply_clock_for_voltage_fail - Test DPM error returns false + * @test: KUnit test context + * + * Verify dm_pp_apply_clock_for_voltage_request returns false when the DPM + * callback fails with an error other than -EOPNOTSUPP. + */ +static void dm_test_apply_clock_for_voltage_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct dm_pp_clock_for_voltage_req req = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + stub_dpm_ctx->display_clock_voltage_ret = -EIO; + + req.clk_type = DM_PP_CLOCK_TYPE_ENGINE_CLK; + req.clocks_in_khz = 500000; + + KUNIT_EXPECT_FALSE(test, dm_pp_apply_clock_for_voltage_request(ctx, &req)); +} + +/* ---- Tests for pp_nv_set_display_count ---- */ + +/** + * dm_test_nv_set_display_count_ok - Test successful display count set + * @test: KUnit test context + * + * Verify pp_nv_set_display_count returns PP_SMU_RESULT_OK on success. + */ +static void dm_test_nv_set_display_count_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->set_active_display_count_ret = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_display_count(&pp_smu, 2), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_set_display_count_unsupported - Test EOPNOTSUPP mapping + * @test: KUnit test context + * + * Verify pp_nv_set_display_count returns PP_SMU_RESULT_UNSUPPORTED when + * the DPM callback returns -EOPNOTSUPP. + */ +static void dm_test_nv_set_display_count_unsupported(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->set_active_display_count_ret = -EOPNOTSUPP; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_display_count(&pp_smu, 2), + (int)PP_SMU_RESULT_UNSUPPORTED); +} + +/** + * dm_test_nv_set_display_count_fail - Test generic error mapping + * @test: KUnit test context + * + * Verify pp_nv_set_display_count returns PP_SMU_RESULT_FAIL on a generic + * DPM error. + */ +static void dm_test_nv_set_display_count_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->set_active_display_count_ret = -EIO; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_display_count(&pp_smu, 2), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_nv_set_voltage_by_freq ---- */ + +/** + * dm_test_nv_set_voltage_by_freq_ok - Test successful voltage-by-freq + * @test: KUnit test context + * + * Verify pp_nv_set_voltage_by_freq returns PP_SMU_RESULT_OK on success. + */ +static void dm_test_nv_set_voltage_by_freq_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_clock_voltage_ret = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_voltage_by_freq(&pp_smu, PP_SMU_NV_DISPCLK, 600), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_set_voltage_by_freq_invalid_id - Test invalid clock id + * @test: KUnit test context + * + * Verify pp_nv_set_voltage_by_freq returns PP_SMU_RESULT_FAIL for an + * unrecognized clock id without calling DPM. + */ +static void dm_test_nv_set_voltage_by_freq_invalid_id(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + KUNIT_EXPECT_EQ(test, + (int)pp_nv_set_voltage_by_freq(&pp_smu, (enum pp_smu_nv_clock_id)0xff, 600), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_nv_set_pstate_handshake_support ---- */ + +/** + * dm_test_nv_pstate_handshake_ok - Test successful pstate handshake + * @test: KUnit test context + * + * Verify pp_nv_set_pstate_handshake_support returns PP_SMU_RESULT_OK + * when the DPM callback succeeds. + */ +static void dm_test_nv_pstate_handshake_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_disable_memory_clock_switch_ret = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_pstate_handshake_support(&pp_smu, true), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_pstate_handshake_fail - Test failed pstate handshake + * @test: KUnit test context + * + * Verify pp_nv_set_pstate_handshake_support returns PP_SMU_RESULT_FAIL + * when the DPM callback returns non-zero. + */ +static void dm_test_nv_pstate_handshake_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_disable_memory_clock_switch_ret = -EIO; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_pstate_handshake_support(&pp_smu, true), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_rn_get_dpm_clock_table ---- */ + +/** + * dm_test_rn_get_dpm_clock_table_ok - Test successful DPM clock table + * @test: KUnit test context + * + * Verify pp_rn_get_dpm_clock_table returns PP_SMU_RESULT_OK on success. + */ +static void dm_test_rn_get_dpm_clock_table_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct dpm_clocks clock_table = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_dpm_clock_table_ret = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_rn_get_dpm_clock_table(&pp_smu, &clock_table), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_rn_get_dpm_clock_table_unsupported - Test EOPNOTSUPP mapping + * @test: KUnit test context + * + * Verify pp_rn_get_dpm_clock_table returns PP_SMU_RESULT_UNSUPPORTED. + */ +static void dm_test_rn_get_dpm_clock_table_unsupported(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct dpm_clocks clock_table = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_dpm_clock_table_ret = -EOPNOTSUPP; + + KUNIT_EXPECT_EQ(test, (int)pp_rn_get_dpm_clock_table(&pp_smu, &clock_table), + (int)PP_SMU_RESULT_UNSUPPORTED); +} + +/** + * dm_test_rn_get_dpm_clock_table_fail - Test generic error mapping + * @test: KUnit test context + * + * Verify pp_rn_get_dpm_clock_table returns PP_SMU_RESULT_FAIL. + */ +static void dm_test_rn_get_dpm_clock_table_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct dpm_clocks clock_table = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_dpm_clock_table_ret = -EIO; + + KUNIT_EXPECT_EQ(test, (int)pp_rn_get_dpm_clock_table(&pp_smu, &clock_table), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_rv_set_wm_ranges ---- */ + +/** + * dm_test_rv_set_wm_ranges - Test Raven watermark range forwarding + * @test: KUnit test context + * + * Verify pp_rv_set_wm_ranges converts watermark ranges via + * build_wm_clock_ranges_soc15 and forwards them to DPM without crashing. + */ +static void dm_test_rv_set_wm_ranges(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct pp_smu_wm_range_sets ranges = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + ranges.num_reader_wm_sets = 1; + ranges.reader_wm_sets[0].wm_inst = 0; + ranges.reader_wm_sets[0].max_drain_clk_mhz = 600; + ranges.reader_wm_sets[0].min_drain_clk_mhz = 300; + + pp_rv_set_wm_ranges(&pp_smu, &ranges); + + /* Reaching here without crash confirms coverage */ + KUNIT_SUCCEED(test); +} + +/* ---- Tests for pp_rv_set_pme_wa_enable ---- */ + +/** + * dm_test_rv_set_pme_wa_enable - Test Raven PME workaround enable + * @test: KUnit test context + * + * Verify pp_rv_set_pme_wa_enable forwards the call to DPM without crashing. + */ +static void dm_test_rv_set_pme_wa_enable(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + pp_rv_set_pme_wa_enable(&pp_smu); + + KUNIT_SUCCEED(test); +} + +/* ---- Tests for pp_rv_set_active_display_count ---- */ + +/** + * dm_test_rv_set_active_display_count - Test Raven display count forwarding + * @test: KUnit test context + * + * Verify pp_rv_set_active_display_count forwards the count to DPM without + * crashing. + */ +static void dm_test_rv_set_active_display_count(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + pp_rv_set_active_display_count(&pp_smu, 2); + + KUNIT_SUCCEED(test); +} + +/* ---- Tests for pp_rv_set_min_deep_sleep_dcfclk ---- */ + +/** + * dm_test_rv_set_min_deep_sleep_dcfclk - Test Raven deep sleep clock + * @test: KUnit test context + * + * Verify pp_rv_set_min_deep_sleep_dcfclk forwards the clock value to DPM + * without crashing. + */ +static void dm_test_rv_set_min_deep_sleep_dcfclk(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + pp_rv_set_min_deep_sleep_dcfclk(&pp_smu, 300); + + KUNIT_SUCCEED(test); +} + +/* ---- Tests for pp_rv_set_hard_min_dcefclk_by_freq ---- */ + +/** + * dm_test_rv_set_hard_min_dcefclk_by_freq - Test Raven hard min DCEFCLK + * @test: KUnit test context + * + * Verify pp_rv_set_hard_min_dcefclk_by_freq forwards the frequency to DPM + * without crashing. + */ +static void dm_test_rv_set_hard_min_dcefclk_by_freq(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + pp_rv_set_hard_min_dcefclk_by_freq(&pp_smu, 600); + + KUNIT_SUCCEED(test); +} + +/* ---- Tests for pp_rv_set_hard_min_fclk_by_freq ---- */ + +/** + * dm_test_rv_set_hard_min_fclk_by_freq - Test Raven hard min FCLK + * @test: KUnit test context + * + * Verify pp_rv_set_hard_min_fclk_by_freq forwards the frequency to DPM + * without crashing. + */ +static void dm_test_rv_set_hard_min_fclk_by_freq(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + pp_rv_set_hard_min_fclk_by_freq(&pp_smu, 800); + + KUNIT_SUCCEED(test); +} + +/* ---- Tests for pp_nv_set_wm_ranges ---- */ + +/** + * dm_test_nv_set_wm_ranges - Test Navi watermark range forwarding + * @test: KUnit test context + * + * Verify pp_nv_set_wm_ranges forwards ranges to DPM and unconditionally + * returns PP_SMU_RESULT_OK. + */ +static void dm_test_nv_set_wm_ranges(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct pp_smu_wm_range_sets ranges = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + + ranges.num_reader_wm_sets = 1; + ranges.reader_wm_sets[0].wm_inst = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_wm_ranges(&pp_smu, &ranges), + (int)PP_SMU_RESULT_OK); +} + +/* ---- Tests for pp_nv_set_min_deep_sleep_dcfclk ---- */ + +/** + * dm_test_nv_set_min_deep_sleep_dcfclk_ok - Test successful deep sleep set + * @test: KUnit test context + * + * Verify pp_nv_set_min_deep_sleep_dcfclk returns PP_SMU_RESULT_OK on success. + */ +static void dm_test_nv_set_min_deep_sleep_dcfclk_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->set_min_deep_sleep_dcefclk_ret = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_min_deep_sleep_dcfclk(&pp_smu, 300), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_set_min_deep_sleep_dcfclk_unsupported - Test EOPNOTSUPP mapping + * @test: KUnit test context + * + * Verify pp_nv_set_min_deep_sleep_dcfclk returns PP_SMU_RESULT_UNSUPPORTED. + */ +static void dm_test_nv_set_min_deep_sleep_dcfclk_unsupported(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->set_min_deep_sleep_dcefclk_ret = -EOPNOTSUPP; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_min_deep_sleep_dcfclk(&pp_smu, 300), + (int)PP_SMU_RESULT_UNSUPPORTED); +} + +/** + * dm_test_nv_set_min_deep_sleep_dcfclk_fail - Test generic error mapping + * @test: KUnit test context + * + * Verify pp_nv_set_min_deep_sleep_dcfclk returns PP_SMU_RESULT_FAIL. + */ +static void dm_test_nv_set_min_deep_sleep_dcfclk_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->set_min_deep_sleep_dcefclk_ret = -EIO; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_min_deep_sleep_dcfclk(&pp_smu, 300), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_nv_set_hard_min_dcefclk_by_freq ---- */ + +/** + * dm_test_nv_set_hard_min_dcefclk_ok - Test successful hard min DCEFCLK + * @test: KUnit test context + * + * Verify pp_nv_set_hard_min_dcefclk_by_freq returns PP_SMU_RESULT_OK. + */ +static void dm_test_nv_set_hard_min_dcefclk_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_clock_voltage_ret = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_hard_min_dcefclk_by_freq(&pp_smu, 600), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_set_hard_min_dcefclk_unsupported - Test EOPNOTSUPP mapping + * @test: KUnit test context + * + * Verify pp_nv_set_hard_min_dcefclk_by_freq returns PP_SMU_RESULT_UNSUPPORTED. + */ +static void dm_test_nv_set_hard_min_dcefclk_unsupported(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_clock_voltage_ret = -EOPNOTSUPP; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_hard_min_dcefclk_by_freq(&pp_smu, 600), + (int)PP_SMU_RESULT_UNSUPPORTED); +} + +/** + * dm_test_nv_set_hard_min_dcefclk_fail - Test generic error mapping + * @test: KUnit test context + * + * Verify pp_nv_set_hard_min_dcefclk_by_freq returns PP_SMU_RESULT_FAIL. + */ +static void dm_test_nv_set_hard_min_dcefclk_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_clock_voltage_ret = -EIO; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_hard_min_dcefclk_by_freq(&pp_smu, 600), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_nv_set_hard_min_uclk_by_freq ---- */ + +/** + * dm_test_nv_set_hard_min_uclk_ok - Test successful hard min UCLK + * @test: KUnit test context + * + * Verify pp_nv_set_hard_min_uclk_by_freq returns PP_SMU_RESULT_OK. + */ +static void dm_test_nv_set_hard_min_uclk_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_clock_voltage_ret = 0; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_hard_min_uclk_by_freq(&pp_smu, 800), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_set_hard_min_uclk_unsupported - Test EOPNOTSUPP mapping + * @test: KUnit test context + * + * Verify pp_nv_set_hard_min_uclk_by_freq returns PP_SMU_RESULT_UNSUPPORTED. + */ +static void dm_test_nv_set_hard_min_uclk_unsupported(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_clock_voltage_ret = -EOPNOTSUPP; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_hard_min_uclk_by_freq(&pp_smu, 800), + (int)PP_SMU_RESULT_UNSUPPORTED); +} + +/** + * dm_test_nv_set_hard_min_uclk_fail - Test generic error mapping + * @test: KUnit test context + * + * Verify pp_nv_set_hard_min_uclk_by_freq returns PP_SMU_RESULT_FAIL. + */ +static void dm_test_nv_set_hard_min_uclk_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->display_clock_voltage_ret = -EIO; + + KUNIT_EXPECT_EQ(test, (int)pp_nv_set_hard_min_uclk_by_freq(&pp_smu, 800), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_nv_get_maximum_sustainable_clocks ---- */ + +/** + * dm_test_nv_get_max_sustainable_clocks_ok - Test successful query + * @test: KUnit test context + * + * Verify pp_nv_get_maximum_sustainable_clocks returns PP_SMU_RESULT_OK. + */ +static void dm_test_nv_get_max_sustainable_clocks_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct pp_smu_nv_clock_table max_clocks = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_max_sustainable_ret = 0; + + KUNIT_EXPECT_EQ(test, + (int)pp_nv_get_maximum_sustainable_clocks(&pp_smu, &max_clocks), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_get_max_sustainable_clocks_unsupported - Test EOPNOTSUPP + * @test: KUnit test context + * + * Verify pp_nv_get_maximum_sustainable_clocks returns PP_SMU_RESULT_UNSUPPORTED. + */ +static void dm_test_nv_get_max_sustainable_clocks_unsupported(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct pp_smu_nv_clock_table max_clocks = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_max_sustainable_ret = -EOPNOTSUPP; + + KUNIT_EXPECT_EQ(test, + (int)pp_nv_get_maximum_sustainable_clocks(&pp_smu, &max_clocks), + (int)PP_SMU_RESULT_UNSUPPORTED); +} + +/** + * dm_test_nv_get_max_sustainable_clocks_fail - Test generic error + * @test: KUnit test context + * + * Verify pp_nv_get_maximum_sustainable_clocks returns PP_SMU_RESULT_FAIL. + */ +static void dm_test_nv_get_max_sustainable_clocks_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + struct pp_smu_nv_clock_table max_clocks = {}; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_max_sustainable_ret = -EIO; + + KUNIT_EXPECT_EQ(test, + (int)pp_nv_get_maximum_sustainable_clocks(&pp_smu, &max_clocks), + (int)PP_SMU_RESULT_FAIL); +} + +/* ---- Tests for pp_nv_get_uclk_dpm_states ---- */ + +/** + * dm_test_nv_get_uclk_dpm_states_ok - Test successful DPM states query + * @test: KUnit test context + * + * Verify pp_nv_get_uclk_dpm_states returns PP_SMU_RESULT_OK. + */ +static void dm_test_nv_get_uclk_dpm_states_ok(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + unsigned int clock_values[4] = {}; + unsigned int num_states = 0; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_uclk_dpm_ret = 0; + + KUNIT_EXPECT_EQ(test, + (int)pp_nv_get_uclk_dpm_states(&pp_smu, clock_values, &num_states), + (int)PP_SMU_RESULT_OK); +} + +/** + * dm_test_nv_get_uclk_dpm_states_unsupported - Test EOPNOTSUPP mapping + * @test: KUnit test context + * + * Verify pp_nv_get_uclk_dpm_states returns PP_SMU_RESULT_UNSUPPORTED. + */ +static void dm_test_nv_get_uclk_dpm_states_unsupported(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + unsigned int clock_values[4] = {}; + unsigned int num_states = 0; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_uclk_dpm_ret = -EOPNOTSUPP; + + KUNIT_EXPECT_EQ(test, + (int)pp_nv_get_uclk_dpm_states(&pp_smu, clock_values, &num_states), + (int)PP_SMU_RESULT_UNSUPPORTED); +} + +/** + * dm_test_nv_get_uclk_dpm_states_fail - Test generic error mapping + * @test: KUnit test context + * + * Verify pp_nv_get_uclk_dpm_states returns PP_SMU_RESULT_FAIL. + */ +static void dm_test_nv_get_uclk_dpm_states_fail(struct kunit *test) +{ + struct amdgpu_device *adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + struct dc_context *ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + struct pp_smu pp_smu = {}; + unsigned int clock_values[4] = {}; + unsigned int num_states = 0; + + KUNIT_ASSERT_NOT_NULL(test, adev); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + setup_stub_dpm(test, adev); + ctx->driver_context = adev; + pp_smu.dm = ctx; + stub_dpm_ctx->get_uclk_dpm_ret = -EIO; + + KUNIT_EXPECT_EQ(test, + (int)pp_nv_get_uclk_dpm_states(&pp_smu, clock_values, &num_states), + (int)PP_SMU_RESULT_FAIL); +} + +static struct kunit_case dm_pp_smu_test_cases[] = { + /* get_default_clock_levels */ + KUNIT_CASE(dm_test_default_clock_levels_display), + KUNIT_CASE(dm_test_default_clock_levels_engine), + KUNIT_CASE(dm_test_default_clock_levels_memory), + KUNIT_CASE(dm_test_default_clock_levels_unknown), + /* dc_to_pp_clock_type */ + KUNIT_CASE(dm_test_dc_to_pp_clock_type_display), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_engine), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_memory), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_dcefclk), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_dcfclk), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_pixelclk), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_fclk), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_phyclk), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_dppclk), + KUNIT_CASE(dm_test_dc_to_pp_clock_type_invalid), + /* pp_to_dc_clock_levels */ + KUNIT_CASE(dm_test_pp_to_dc_clock_levels_within_limit), + KUNIT_CASE(dm_test_pp_to_dc_clock_levels_caps_at_max), + /* pp_to_dc_clock_levels_with_latency */ + KUNIT_CASE(dm_test_pp_to_dc_clock_levels_latency_within_limit), + KUNIT_CASE(dm_test_pp_to_dc_clock_levels_latency_caps_at_max), + /* pp_to_dc_clock_levels_with_voltage */ + KUNIT_CASE(dm_test_pp_to_dc_clock_levels_voltage_within_limit), + KUNIT_CASE(dm_test_pp_to_dc_clock_levels_voltage_caps_at_max), + /* dm_pp_get_funcs */ + KUNIT_CASE(dm_test_get_funcs_rv), + KUNIT_CASE(dm_test_get_funcs_rv_101), + KUNIT_CASE(dm_test_get_funcs_nv), + KUNIT_CASE(dm_test_get_funcs_rn), + KUNIT_CASE(dm_test_get_funcs_unsupported), + /* amdgpu_device-backed entry points */ + KUNIT_CASE(dm_test_apply_display_requirements_dpm_disabled), + KUNIT_CASE(dm_test_apply_clock_for_voltage_invalid_type), + /* build_pm_display_cfg */ + KUNIT_CASE(dm_test_build_pm_display_cfg_scalar_fields), + KUNIT_CASE(dm_test_build_pm_display_cfg_per_display), + /* build_wm_clock_ranges_soc15 */ + KUNIT_CASE(dm_test_build_wm_clock_ranges_dmif), + KUNIT_CASE(dm_test_build_wm_clock_ranges_mcif), + /* cap_clock_levels_to_validation */ + KUNIT_CASE(dm_test_cap_clock_levels_engine_caps), + KUNIT_CASE(dm_test_cap_clock_levels_engine_first_exceeds), + KUNIT_CASE(dm_test_cap_clock_levels_memory_caps), + KUNIT_CASE(dm_test_cap_clock_levels_within_limit), + KUNIT_CASE(dm_test_cap_clock_levels_other_type), + /* pp_smu_nv_clock_id_to_pp */ + KUNIT_CASE(dm_test_nv_clock_id_dispclk), + KUNIT_CASE(dm_test_nv_clock_id_phyclk), + KUNIT_CASE(dm_test_nv_clock_id_pixelclk), + KUNIT_CASE(dm_test_nv_clock_id_invalid), + /* dm_pp_apply_display_requirements (DPM enabled) */ + KUNIT_CASE(dm_test_apply_display_requirements_dpm_enabled), + /* dm_pp_get_clock_levels_by_type */ + KUNIT_CASE(dm_test_get_clock_levels_by_type_dpm_error), + KUNIT_CASE(dm_test_get_clock_levels_by_type_success), + KUNIT_CASE(dm_test_get_clock_levels_by_type_validation_fallback), + /* dm_pp_get_clock_levels_by_type_with_latency */ + KUNIT_CASE(dm_test_get_clock_levels_with_latency_success), + KUNIT_CASE(dm_test_get_clock_levels_with_latency_failure), + /* dm_pp_get_clock_levels_by_type_with_voltage */ + KUNIT_CASE(dm_test_get_clock_levels_with_voltage_success), + KUNIT_CASE(dm_test_get_clock_levels_with_voltage_failure), + /* dm_pp_notify_wm_clock_changes */ + KUNIT_CASE(dm_test_notify_wm_clock_changes_polaris), + KUNIT_CASE(dm_test_notify_wm_clock_changes_non_polaris), + /* dm_pp_apply_clock_for_voltage_request (with DPM) */ + KUNIT_CASE(dm_test_apply_clock_for_voltage_success), + KUNIT_CASE(dm_test_apply_clock_for_voltage_eopnotsupp), + KUNIT_CASE(dm_test_apply_clock_for_voltage_fail), + /* pp_nv_set_display_count */ + KUNIT_CASE(dm_test_nv_set_display_count_ok), + KUNIT_CASE(dm_test_nv_set_display_count_unsupported), + KUNIT_CASE(dm_test_nv_set_display_count_fail), + /* pp_nv_set_voltage_by_freq */ + KUNIT_CASE(dm_test_nv_set_voltage_by_freq_ok), + KUNIT_CASE(dm_test_nv_set_voltage_by_freq_invalid_id), + /* pp_nv_set_pstate_handshake_support */ + KUNIT_CASE(dm_test_nv_pstate_handshake_ok), + KUNIT_CASE(dm_test_nv_pstate_handshake_fail), + /* pp_rn_get_dpm_clock_table */ + KUNIT_CASE(dm_test_rn_get_dpm_clock_table_ok), + KUNIT_CASE(dm_test_rn_get_dpm_clock_table_unsupported), + KUNIT_CASE(dm_test_rn_get_dpm_clock_table_fail), + /* pp_rv_set_wm_ranges */ + KUNIT_CASE(dm_test_rv_set_wm_ranges), + /* pp_rv_set_pme_wa_enable */ + KUNIT_CASE(dm_test_rv_set_pme_wa_enable), + /* pp_rv_set_active_display_count */ + KUNIT_CASE(dm_test_rv_set_active_display_count), + /* pp_rv_set_min_deep_sleep_dcfclk */ + KUNIT_CASE(dm_test_rv_set_min_deep_sleep_dcfclk), + /* pp_rv_set_hard_min_dcefclk_by_freq */ + KUNIT_CASE(dm_test_rv_set_hard_min_dcefclk_by_freq), + /* pp_rv_set_hard_min_fclk_by_freq */ + KUNIT_CASE(dm_test_rv_set_hard_min_fclk_by_freq), + /* pp_nv_set_wm_ranges */ + KUNIT_CASE(dm_test_nv_set_wm_ranges), + /* pp_nv_set_min_deep_sleep_dcfclk */ + KUNIT_CASE(dm_test_nv_set_min_deep_sleep_dcfclk_ok), + KUNIT_CASE(dm_test_nv_set_min_deep_sleep_dcfclk_unsupported), + KUNIT_CASE(dm_test_nv_set_min_deep_sleep_dcfclk_fail), + /* pp_nv_set_hard_min_dcefclk_by_freq */ + KUNIT_CASE(dm_test_nv_set_hard_min_dcefclk_ok), + KUNIT_CASE(dm_test_nv_set_hard_min_dcefclk_unsupported), + KUNIT_CASE(dm_test_nv_set_hard_min_dcefclk_fail), + /* pp_nv_set_hard_min_uclk_by_freq */ + KUNIT_CASE(dm_test_nv_set_hard_min_uclk_ok), + KUNIT_CASE(dm_test_nv_set_hard_min_uclk_unsupported), + KUNIT_CASE(dm_test_nv_set_hard_min_uclk_fail), + /* pp_nv_get_maximum_sustainable_clocks */ + KUNIT_CASE(dm_test_nv_get_max_sustainable_clocks_ok), + KUNIT_CASE(dm_test_nv_get_max_sustainable_clocks_unsupported), + KUNIT_CASE(dm_test_nv_get_max_sustainable_clocks_fail), + /* pp_nv_get_uclk_dpm_states */ + KUNIT_CASE(dm_test_nv_get_uclk_dpm_states_ok), + KUNIT_CASE(dm_test_nv_get_uclk_dpm_states_unsupported), + KUNIT_CASE(dm_test_nv_get_uclk_dpm_states_fail), + {} +}; + +static struct kunit_suite dm_pp_smu_test_suite = { + .name = "amdgpu_dm_pp_smu", + .test_cases = dm_pp_smu_test_cases, +}; + +kunit_test_suite(dm_pp_smu_test_suite); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_pp_smu"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c index 09084f70a405..09bd98e93047 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_psr_test.c @@ -7,29 +7,331 @@ #include +#include "dc.h" +#include "core_types.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" #include "amdgpu_dm_psr.h" +#include "amdgpu_dm_kunit_test_helpers.h" +#include "power_helpers.h" -/* - * Helper: allocate and zero-initialise a dc_link sufficient for - * amdgpu_dm_psr_fill_caps() testing. The function only accesses - * embedded members (dpcd_caps, psr_settings) so no pointer fields - * need to be wired up. - */ -static struct dc_link *alloc_test_link(struct kunit *test) +static struct dc_stream_state *alloc_test_psr_stream(struct kunit *test) { struct dc_link *link; - link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, link); + link = dm_kunit_alloc_link(test); + link->psr_settings.psr_feature_enabled = true; + + return dm_kunit_alloc_stream(test, link); +} + +static struct core_power *create_test_power_module(struct kunit *test, + struct dc_stream_state *stream, struct psr_caps *caps) +{ + struct core_power *core_power; + + core_power = kunit_kzalloc(test, sizeof(*core_power), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, core_power); + + core_power->map = kunit_kzalloc(test, sizeof(*core_power->map), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, core_power->map); + + core_power->map[0].stream = stream; + core_power->map[0].caps = caps; + core_power->map[0].psr_events = psr_event_vsync; + core_power->num_entities = 1; + + return core_power; +} + +static struct dc_link *alloc_test_psrsu_link(struct kunit *test) +{ + struct dc_link *link = dm_kunit_alloc_link(test); + struct dc_context *ctx; + struct dc *dc; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dc); + + link->ctx = ctx; + ctx->dc = dc; + dc->ctx = ctx; + dc->caps.dmcub_support = true; + ctx->dce_version = DCN_VERSION_3_1; + link->dpcd_caps.edp_rev = DP_EDP_14; + link->dpcd_caps.psr_info.psr_version = DP_PSR2_WITH_Y_COORD_ET_SUPPORTED; + link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 1; + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED = 1; return link; } +static struct dc_link *alloc_test_psr_caps_link(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + + link->ctx->dc->caps.dmub_caps.psr = true; + link->connector_signal = SIGNAL_TYPE_EDP; + link->type = dc_connection_single; + + return link; +} + +static struct amdgpu_dm_connector *alloc_test_aconnector(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector; + + aconnector = kunit_kzalloc(test, sizeof(*aconnector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, aconnector); + + return aconnector; +} + +/* Tests for link_supports_psrsu() */ + +/** + * dm_test_link_supports_psrsu_no_dmcub() - DMCUB support is required. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_no_dmcub(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + + link->ctx->dc->caps.dmcub_support = false; + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); +} + +/** + * dm_test_link_supports_psrsu_old_dcn() - DCN version 3.1 or newer is required. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_old_dcn(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + + link->ctx->dce_version = DCN_VERSION_3_0; + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); +} + +/** + * dm_test_link_supports_psrsu_panel_unsupported() - Panel PSR-SU caps are required. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_panel_unsupported(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + + link->dpcd_caps.psr_info.psr_version = 0; + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); +} + +/** + * dm_test_link_supports_psrsu_missing_alpm() - AUX wake ALPM is required. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_missing_alpm(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + + link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 0; + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); +} + +/** + * dm_test_link_supports_psrsu_missing_y_coordinate() - Y coordinate support is required. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_missing_y_coordinate(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED = 0; + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); +} + +/** + * dm_test_link_supports_psrsu_missing_granularity() - Required granularity must + * be reported by the panel. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_missing_granularity(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + + link->dpcd_caps.psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED = 1; + link->dpcd_caps.psr_info.psr2_su_y_granularity_cap = 0; + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); +} + +/** + * dm_test_link_supports_psrsu_debug_mask_disabled() - Debug mask disables PSR-SU. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_debug_mask_disabled(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + unsigned int old_debug_mask; + + old_debug_mask = amdgpu_dm_psr_get_dc_debug_mask(); + amdgpu_dm_psr_set_dc_debug_mask(old_debug_mask | DC_DISABLE_PSR_SU); + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); + amdgpu_dm_psr_set_dc_debug_mask(old_debug_mask); +} + +/** + * dm_test_link_supports_psrsu_temporarily_disabled() - Supported panels still + * return false while PSR-SU is temporarily disabled. + * @test: KUnit test context. + */ +static void dm_test_link_supports_psrsu_temporarily_disabled(struct kunit *test) +{ + struct dc_link *link = alloc_test_psrsu_link(test); + unsigned int old_debug_mask; + + old_debug_mask = amdgpu_dm_psr_get_dc_debug_mask(); + amdgpu_dm_psr_set_dc_debug_mask(old_debug_mask & ~DC_DISABLE_PSR_SU); + + KUNIT_EXPECT_FALSE(test, link_supports_psrsu(link)); + amdgpu_dm_psr_set_dc_debug_mask(old_debug_mask); +} + +/* End of tests for link_supports_psrsu() */ + +/* Tests for amdgpu_dm_set_psr_caps() */ + +/** + * dm_test_set_psr_caps_null_link() - NULL link is rejected. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_null_link(struct kunit *test) +{ + struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(NULL, aconnector)); +} + +/** + * dm_test_set_psr_caps_null_connector() - NULL connector is rejected. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_null_connector(struct kunit *test) +{ + struct dc_link *link = alloc_test_psr_caps_link(test); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(link, NULL)); +} + +/** + * dm_test_set_psr_caps_no_dmub_psr() - DMUB PSR capability is required. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_no_dmub_psr(struct kunit *test) +{ + struct dc_link *link = alloc_test_psr_caps_link(test); + struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test); + + link->psr_settings.psr_version = DC_PSR_VERSION_1; + link->ctx->dc->caps.dmub_caps.psr = false; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(link, aconnector)); + KUNIT_EXPECT_EQ(test, link->psr_settings.psr_version, + DC_PSR_VERSION_UNSUPPORTED); +} + +/** + * dm_test_set_psr_caps_non_edp() - Only eDP links can enable PSR. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_non_edp(struct kunit *test) +{ + struct dc_link *link = alloc_test_psr_caps_link(test); + struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test); + + link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(link, aconnector)); +} + +/** + * dm_test_set_psr_caps_disconnected() - Disconnected links cannot enable PSR. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_disconnected(struct kunit *test) +{ + struct dc_link *link = alloc_test_psr_caps_link(test); + struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test); + + link->type = dc_connection_none; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(link, aconnector)); +} + +/** + * dm_test_set_psr_caps_no_dpcd_psr() - DPCD PSR version is required. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_no_dpcd_psr(struct kunit *test) +{ + struct dc_link *link = alloc_test_psr_caps_link(test); + struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test); + + link->dpcd_caps.psr_info.psr_version = 0; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(link, aconnector)); +} + +/** + * dm_test_set_psr_caps_edp1_disabled() - eDP panel instance 1 is blocked. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_edp1_disabled(struct kunit *test) +{ + struct dc_link *link = alloc_test_psr_caps_link(test); + struct dc_link *edp0 = dm_kunit_alloc_link(test); + struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test); + struct dc *dc = link->ctx->dc; + + edp0->connector_signal = SIGNAL_TYPE_EDP; + dc->links[0] = edp0; + dc->links[1] = link; + dc->link_count = 2; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_psr_caps(link, aconnector)); +} + +/** + * dm_test_set_psr_caps_success_psr1() - Valid eDP link enables PSR1 caps. + * @test: KUnit test context. + */ +static void dm_test_set_psr_caps_success_psr1(struct kunit *test) +{ + struct dc_link *link = alloc_test_psr_caps_link(test); + struct amdgpu_dm_connector *aconnector = alloc_test_aconnector(test); + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_set_psr_caps(link, aconnector)); + KUNIT_EXPECT_EQ(test, link->psr_settings.psr_version, DC_PSR_VERSION_1); + KUNIT_EXPECT_EQ(test, (int)aconnector->psr_caps.psr_version, 1); + KUNIT_EXPECT_EQ(test, (int)aconnector->psr_caps.support_ver, + DP_PSR2_WITH_Y_COORD_ET_SUPPORTED); +} + +/* End of tests for amdgpu_dm_set_psr_caps() */ + /* Tests for amdgpu_dm_psr_fill_caps() — PSR version mapping */ static void dm_test_psr_fill_caps_version_1(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -42,7 +344,7 @@ static void dm_test_psr_fill_caps_version_1(struct kunit *test) static void dm_test_psr_fill_caps_version_su1(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -55,7 +357,7 @@ static void dm_test_psr_fill_caps_version_su1(struct kunit *test) static void dm_test_psr_fill_caps_version_unsupported(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -74,7 +376,7 @@ static void dm_test_psr_fill_caps_version_unsupported(struct kunit *test) static void dm_test_psr_fill_caps_setup_time_zero(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -88,7 +390,7 @@ static void dm_test_psr_fill_caps_setup_time_zero(struct kunit *test) static void dm_test_psr_fill_caps_setup_time_mid(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -102,7 +404,7 @@ static void dm_test_psr_fill_caps_setup_time_mid(struct kunit *test) static void dm_test_psr_fill_caps_setup_time_max(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -118,7 +420,7 @@ static void dm_test_psr_fill_caps_setup_time_max(struct kunit *test) static void dm_test_psr_fill_caps_link_training_required(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -131,7 +433,7 @@ static void dm_test_psr_fill_caps_link_training_required(struct kunit *test) static void dm_test_psr_fill_caps_link_training_not_required(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -146,7 +448,7 @@ static void dm_test_psr_fill_caps_link_training_not_required(struct kunit *test) static void dm_test_psr_fill_caps_dpcd_fields(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -172,7 +474,7 @@ static void dm_test_psr_fill_caps_dpcd_fields(struct kunit *test) static void dm_test_psr_fill_caps_dpcd_fields_unset(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0xFF, sizeof(caps)); @@ -193,7 +495,7 @@ static void dm_test_psr_fill_caps_dpcd_fields_unset(struct kunit *test) static void dm_test_psr_fill_caps_rate_control_always_zero(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; /* Pre-fill caps with non-zero to verify overwrite */ @@ -206,7 +508,7 @@ static void dm_test_psr_fill_caps_rate_control_always_zero(struct kunit *test) static void dm_test_psr_fill_caps_power_opts_z10_always_set(struct kunit *test) { - struct dc_link *link = alloc_test_link(test); + struct dc_link *link = dm_kunit_alloc_link(test); struct psr_caps caps; memset(&caps, 0, sizeof(caps)); @@ -221,6 +523,24 @@ static void dm_test_psr_fill_caps_power_opts_z10_always_set(struct kunit *test) (caps.psr_power_opt_flag & psr_power_opt_z10_static_screen) != 0); } + +static void dm_test_psr_fill_caps_power_opts_smu_opt_set(struct kunit *test) +{ + struct dc_link *link = dm_kunit_alloc_link(test); + struct psr_caps caps; + unsigned int old_feature_mask; + + memset(&caps, 0, sizeof(caps)); + old_feature_mask = amdgpu_dm_psr_get_dc_feature_mask(); + amdgpu_dm_psr_set_dc_feature_mask(old_feature_mask | DC_PSR_ALLOW_SMU_OPT); + + amdgpu_dm_psr_fill_caps(link, &caps); + amdgpu_dm_psr_set_dc_feature_mask(old_feature_mask); + + KUNIT_EXPECT_TRUE(test, + (caps.psr_power_opt_flag & + psr_power_opt_smu_opt_static_screen) != 0); +} /* End of tests for amdgpu_dm_psr_fill_caps() */ /* Tests for amdgpu_dm_psr_set_event() — early-exit validation guards */ @@ -258,9 +578,155 @@ static void dm_test_psr_set_event_psr_not_enabled(struct kunit *test) KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_set_event(NULL, stream, true, psr_event_vsync, false)); } + +/** + * dm_test_psr_set_event_get_event_fails() - Failed power event read returns false. + * @test: KUnit test context. + */ +static void dm_test_psr_set_event_get_event_fails(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct dc_stream_state *stream = alloc_test_psr_stream(test); + + dm->power_module = NULL; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_set_event(dm, stream, true, psr_event_vsync, false)); +} + +/** + * dm_test_psr_set_event_already_set() - Already set event returns true. + * @test: KUnit test context. + */ +static void dm_test_psr_set_event_already_set(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct dc_stream_state *stream = alloc_test_psr_stream(test); + struct psr_caps caps = {0}; + struct core_power *core_power; + + caps.psr_version = 1; + core_power = create_test_power_module(test, stream, &caps); + dm->power_module = &core_power->mod_public; + + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_psr_set_event(dm, stream, true, psr_event_vsync, false)); + KUNIT_EXPECT_EQ(test, core_power->map[0].psr_events, + (unsigned int)psr_event_vsync); +} + +/** + * dm_test_psr_set_event_updates_event() - Changed event delegates to mod_power. + * @test: KUnit test context. + */ +static void dm_test_psr_set_event_updates_event(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct dc_stream_state *stream = alloc_test_psr_stream(test); + struct psr_caps caps = {0}; + struct core_power *core_power; + + caps.psr_version = 1; + core_power = create_test_power_module(test, stream, &caps); + dm->power_module = &core_power->mod_public; + + KUNIT_EXPECT_TRUE(test, + amdgpu_dm_psr_set_event(dm, stream, true, psr_event_full_screen, false)); + KUNIT_EXPECT_EQ(test, core_power->map[0].psr_events, + (unsigned int)(psr_event_vsync | psr_event_full_screen)); +} /* End of tests for amdgpu_dm_psr_set_event() */ +/* Tests for amdgpu_dm_psr_is_active_allowed() */ + +/** + * dm_test_psr_is_active_allowed_no_streams() - Empty DC state disallows PSR. + * @test: KUnit test context. + */ +static void dm_test_psr_is_active_allowed_no_streams(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_is_active_allowed(dm)); +} + +/** + * dm_test_psr_is_active_allowed_null_link() - Streams without links are skipped. + * @test: KUnit test context. + */ +static void dm_test_psr_is_active_allowed_null_link(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct dc_state *state = dm->dc->current_state; + + dm_kunit_add_stream_to_state(test, state, 0, NULL); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_is_active_allowed(dm)); +} + +/** + * dm_test_psr_is_active_allowed_requires_enabled_and_allowed() - Both link flags + * must be set before PSR active is allowed. + * @test: KUnit test context. + */ +static void dm_test_psr_is_active_allowed_requires_enabled_and_allowed(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct dc_state *state = dm->dc->current_state; + struct dc_link *link = dm_kunit_alloc_link(test); + + dm_kunit_add_stream_to_state(test, state, 0, link); + link->psr_settings.psr_allow_active = true; + KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_is_active_allowed(dm)); + + link->psr_settings.psr_allow_active = false; + link->psr_settings.psr_feature_enabled = true; + KUNIT_EXPECT_FALSE(test, amdgpu_dm_psr_is_active_allowed(dm)); +} + +/** + * dm_test_psr_is_active_allowed_any_stream() - Any enabled and allowed stream + * permits active PSR. + * @test: KUnit test context. + */ +static void dm_test_psr_is_active_allowed_any_stream(struct kunit *test) +{ + struct amdgpu_display_manager *dm = dm_kunit_alloc_dm(test); + struct dc_state *state = dm->dc->current_state; + struct dc_link *disabled_link = dm_kunit_alloc_link(test); + struct dc_link *allowed_link = dm_kunit_alloc_link(test); + + disabled_link->psr_settings.psr_allow_active = true; + allowed_link->psr_settings.psr_feature_enabled = true; + allowed_link->psr_settings.psr_allow_active = true; + + dm_kunit_add_stream_to_state(test, state, 0, disabled_link); + dm_kunit_add_stream_to_state(test, state, 1, allowed_link); + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_psr_is_active_allowed(dm)); +} + +/* End of tests for amdgpu_dm_psr_is_active_allowed() */ + static struct kunit_case dm_psr_test_cases[] = { + /* link_supports_psrsu */ + KUNIT_CASE(dm_test_link_supports_psrsu_no_dmcub), + KUNIT_CASE(dm_test_link_supports_psrsu_old_dcn), + KUNIT_CASE(dm_test_link_supports_psrsu_panel_unsupported), + KUNIT_CASE(dm_test_link_supports_psrsu_missing_alpm), + KUNIT_CASE(dm_test_link_supports_psrsu_missing_y_coordinate), + KUNIT_CASE(dm_test_link_supports_psrsu_missing_granularity), + KUNIT_CASE(dm_test_link_supports_psrsu_debug_mask_disabled), + KUNIT_CASE(dm_test_link_supports_psrsu_temporarily_disabled), + /* amdgpu_dm_set_psr_caps */ + KUNIT_CASE(dm_test_set_psr_caps_null_link), + KUNIT_CASE(dm_test_set_psr_caps_null_connector), + KUNIT_CASE(dm_test_set_psr_caps_no_dmub_psr), + KUNIT_CASE(dm_test_set_psr_caps_non_edp), + KUNIT_CASE(dm_test_set_psr_caps_disconnected), + KUNIT_CASE(dm_test_set_psr_caps_no_dpcd_psr), + KUNIT_CASE(dm_test_set_psr_caps_edp1_disabled), + KUNIT_CASE(dm_test_set_psr_caps_success_psr1), + /* amdgpu_dm_psr_fill_caps */ KUNIT_CASE(dm_test_psr_fill_caps_version_1), KUNIT_CASE(dm_test_psr_fill_caps_version_su1), KUNIT_CASE(dm_test_psr_fill_caps_version_unsupported), @@ -273,9 +739,19 @@ static struct kunit_case dm_psr_test_cases[] = { KUNIT_CASE(dm_test_psr_fill_caps_dpcd_fields_unset), KUNIT_CASE(dm_test_psr_fill_caps_rate_control_always_zero), KUNIT_CASE(dm_test_psr_fill_caps_power_opts_z10_always_set), + KUNIT_CASE(dm_test_psr_fill_caps_power_opts_smu_opt_set), + /* amdgpu_dm_psr_set_event */ KUNIT_CASE(dm_test_psr_set_event_null_stream), KUNIT_CASE(dm_test_psr_set_event_null_link), KUNIT_CASE(dm_test_psr_set_event_psr_not_enabled), + KUNIT_CASE(dm_test_psr_set_event_get_event_fails), + KUNIT_CASE(dm_test_psr_set_event_already_set), + KUNIT_CASE(dm_test_psr_set_event_updates_event), + /* amdgpu_dm_psr_is_active_allowed */ + KUNIT_CASE(dm_test_psr_is_active_allowed_no_streams), + KUNIT_CASE(dm_test_psr_is_active_allowed_null_link), + KUNIT_CASE(dm_test_psr_is_active_allowed_requires_enabled_and_allowed), + KUNIT_CASE(dm_test_psr_is_active_allowed_any_stream), {} }; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c new file mode 100644 index 000000000000..a09f31ee0a2a --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_quirks_test.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_quirks.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include + +#include "dc.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" + +/* Tests for retrieve_dmi_info() */ + +/* + * Verify that retrieve_dmi_info() always initialises aux_hpd_discon_quirk to + * false, even when the caller had previously set it to true. + */ +/** + * dm_test_quirks_aux_hpd_discon_reset - Test Quirks aux hpd discon reset + * @test: The KUnit test context + */ +static void dm_test_quirks_aux_hpd_discon_reset(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + + dm->aux_hpd_discon_quirk = true; + + retrieve_dmi_info(dm); + + /* + * In a KUnit / UML environment no real DMI table is present, so + * dmi_check_system() returns 0 and retrieve_dmi_info() leaves the + * quirk at its initialised-to-false value. + */ + KUNIT_EXPECT_FALSE(test, dm->aux_hpd_discon_quirk); +} + +/* + * Verify that retrieve_dmi_info() always initialises edp0_on_dp1_quirk to + * false, even when the caller had previously set it to true. + */ +/** + * dm_test_quirks_edp0_on_dp1_reset - Test Quirks edp0 on dp1 reset + * @test: The KUnit test context + */ +static void dm_test_quirks_edp0_on_dp1_reset(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + + dm->edp0_on_dp1_quirk = true; + + retrieve_dmi_info(dm); + + KUNIT_EXPECT_FALSE(test, dm->edp0_on_dp1_quirk); +} + +/* + * Verify that when no DMI match is found both quirks remain false after a + * fresh (zero-initialised) dm is passed to retrieve_dmi_info(). + */ +/** + * dm_test_quirks_no_dmi_match_both_false - Test Quirks no dmi match both false + * @test: The KUnit test context + */ +static void dm_test_quirks_no_dmi_match_both_false(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dm); + + retrieve_dmi_info(dm); + + KUNIT_EXPECT_FALSE(test, dm->aux_hpd_discon_quirk); + KUNIT_EXPECT_FALSE(test, dm->edp0_on_dp1_quirk); +} + +static struct kunit_case amdgpu_dm_quirks_tests[] = { + /* retrieve_dmi_info */ + KUNIT_CASE(dm_test_quirks_aux_hpd_discon_reset), + KUNIT_CASE(dm_test_quirks_edp0_on_dp1_reset), + KUNIT_CASE(dm_test_quirks_no_dmi_match_both_false), + {} +}; + +static struct kunit_suite amdgpu_dm_quirks_test_suite = { + .name = "amdgpu_dm_quirks", + .test_cases = amdgpu_dm_quirks_tests, +}; + +kunit_test_suite(amdgpu_dm_quirks_test_suite); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_quirks"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_replay_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_replay_test.c index 28ff8bbcc0f7..6f633b1bbaca 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_replay_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_replay_test.c @@ -8,12 +8,13 @@ #include #include "dc.h" +#include "dc_dmub_srv.h" #include "amdgpu_mode.h" #include "amdgpu_dm.h" - -/* Extern declaration for the function under test */ -extern bool amdgpu_dm_link_supports_replay(struct dc_link *link, - struct amdgpu_dm_connector *aconnector); +#include "amdgpu_dm_replay.h" +#include "amdgpu_dm_kunit_test_helpers.h" +#include "modules/power/power_helpers.h" +#include "dmub/dmub_srv.h" /* * Helper: allocate a dc_link, amdgpu_dm_connector, and dm_connector_state @@ -23,6 +24,9 @@ struct replay_test_ctx { struct dc_link *link; struct amdgpu_dm_connector *aconnector; struct dm_connector_state *dm_state; + struct dc *dc; + struct dc_context *dc_ctx; + struct dc_stream_state *stream; }; static struct replay_test_ctx *alloc_replay_ctx(struct kunit *test) @@ -32,8 +36,9 @@ static struct replay_test_ctx *alloc_replay_ctx(struct kunit *test) ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, ctx); - ctx->link = kunit_kzalloc(test, sizeof(*ctx->link), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, ctx->link); + ctx->link = dm_kunit_alloc_link_with_ctx(test); + ctx->dc_ctx = ctx->link->ctx; + ctx->dc = ctx->dc_ctx->dc; ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector); @@ -41,6 +46,8 @@ static struct replay_test_ctx *alloc_replay_ctx(struct kunit *test) ctx->dm_state = kunit_kzalloc(test, sizeof(*ctx->dm_state), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, ctx->dm_state); + ctx->stream = dm_kunit_alloc_stream(test, ctx->link); + /* Wire connector state so to_dm_connector_state() works */ ctx->aconnector->base.state = &ctx->dm_state->base; @@ -55,6 +62,7 @@ static void set_all_replay_caps(struct replay_test_ctx *ctx) { ctx->dm_state->freesync_capable = true; ctx->aconnector->vsdb_info.replay_mode = true; + ctx->link->connector_signal = SIGNAL_TYPE_EDP; ctx->link->dpcd_caps.edp_rev = EDP_REVISION_13; ctx->link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP = 1; ctx->link->dpcd_caps.adaptive_sync_caps.dp_adap_sync_caps.bits.ADAPTIVE_SYNC_SDP_SUPPORT = 1; @@ -181,7 +189,398 @@ static void dm_test_replay_both_deviations_zero(struct kunit *test) /* End of tests for amdgpu_dm_link_supports_replay() */ +/* Tests for amdgpu_dm_set_replay_caps() */ + +/** + * dm_test_replay_set_caps_already_supported - Verify cached Replay support + * @test: KUnit test context + * + * When replay_supported is already set, amdgpu_dm_set_replay_caps() should + * return true without revalidating the link capabilities. + */ +static void dm_test_replay_set_caps_already_supported(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + ctx->link->replay_settings.config.replay_supported = true; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_set_replay_caps(ctx->link, ctx->aconnector)); +} + +/** + * dm_test_replay_set_caps_non_embedded_signal - Verify non-eDP rejection + * @test: KUnit test context + * + * When the link signal is not embedded, amdgpu_dm_set_replay_caps() should + * reject Replay even if the sink capability fields are otherwise valid. + */ +static void dm_test_replay_set_caps_non_embedded_signal(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + set_all_replay_caps(ctx); + ctx->link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_replay_caps(ctx->link, ctx->aconnector)); +} + +/** + * dm_test_replay_set_caps_disallowed_by_panel - Verify panel policy rejection + * @test: KUnit test context + * + * When the panel configuration disallows Replay, amdgpu_dm_set_replay_caps() + * should return false before accepting the capability set. + */ +static void dm_test_replay_set_caps_disallowed_by_panel(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + set_all_replay_caps(ctx); + ctx->link->panel_config.psr.disallow_replay = true; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_replay_caps(ctx->link, ctx->aconnector)); +} + +/** + * dm_test_replay_set_caps_link_not_supported - Verify capability rejection + * @test: KUnit test context + * + * When amdgpu_dm_link_supports_replay() rejects the link, the higher-level + * Replay setup helper should also return false. + */ +static void dm_test_replay_set_caps_link_not_supported(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + set_all_replay_caps(ctx); + ctx->dm_state->freesync_capable = false; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_replay_caps(ctx->link, ctx->aconnector)); +} + +/** + * dm_test_replay_set_caps_missing_dmub_srv - Verify missing DMUB rejection + * @test: KUnit test context + * + * When the link and connector support Replay but no DMUB service is available, + * amdgpu_dm_set_replay_caps() should return false. + */ +static void dm_test_replay_set_caps_missing_dmub_srv(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + set_all_replay_caps(ctx); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_set_replay_caps(ctx->link, ctx->aconnector)); +} + +/** + * dm_test_replay_set_caps_success - Verify successful Replay configuration + * @test: KUnit test context + * + * When all prerequisites are met (embedded signal, panel allows replay, link + * supports replay, DMUB present with replay support), amdgpu_dm_set_replay_caps() + * should configure the link replay settings and return true. + */ +static void dm_test_replay_set_caps_success(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + struct dc_dmub_srv *dmub_srv; + struct dmub_srv *dmub; + + set_all_replay_caps(ctx); + + dmub_srv = kunit_kzalloc(test, sizeof(*dmub_srv), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dmub_srv); + + dmub = kunit_kzalloc(test, sizeof(*dmub), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dmub); + + dmub->feature_caps.replay_supported = 1; + dmub_srv->dmub = dmub; + ctx->dc_ctx->dmub_srv = dmub_srv; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_set_replay_caps(ctx->link, ctx->aconnector)); + KUNIT_EXPECT_TRUE(test, ctx->link->replay_settings.config.replay_supported); +} + +/* Tests for amdgpu_dm_link_setup_replay() */ + +/** + * dm_test_replay_link_setup_null_stream - Verify NULL stream rejection + * @test: KUnit test context + * + * amdgpu_dm_link_setup_replay() should return false when no stream is provided. + */ +static void dm_test_replay_link_setup_null_stream(struct kunit *test) +{ + struct mod_vrr_params vrr_params = { 0 }; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_link_setup_replay(NULL, &vrr_params)); +} + +/** + * dm_test_replay_link_setup_null_link - Verify NULL stream link rejection + * @test: KUnit test context + * + * amdgpu_dm_link_setup_replay() should return false when the stream has no + * associated link. + */ +static void dm_test_replay_link_setup_null_link(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + struct mod_vrr_params vrr_params = { 0 }; + + ctx->stream->link = NULL; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_link_setup_replay(ctx->stream, &vrr_params)); +} + +/** + * dm_test_replay_link_setup_null_vrr_params - Verify NULL VRR params rejection + * @test: KUnit test context + * + * amdgpu_dm_link_setup_replay() should return false when VRR parameters are + * not supplied. + */ +static void dm_test_replay_link_setup_null_vrr_params(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_link_setup_replay(ctx->stream, NULL)); +} + +/** + * dm_test_replay_link_setup_not_supported - Verify unsupported Replay rejection + * @test: KUnit test context + * + * amdgpu_dm_link_setup_replay() should return false when Replay is not marked + * supported on the link configuration. + */ +static void dm_test_replay_link_setup_not_supported(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + struct mod_vrr_params vrr_params = { 0 }; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_link_setup_replay(ctx->stream, &vrr_params)); +} + +/** + * dm_test_replay_link_setup_already_enabled - Verify enabled Replay success + * @test: KUnit test context + * + * When Replay is already enabled, amdgpu_dm_link_setup_replay() should return + * true without recalculating coasting vtotal state. + */ +static void dm_test_replay_link_setup_already_enabled(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + struct mod_vrr_params vrr_params = { 0 }; + + ctx->link->replay_settings.config.replay_supported = true; + ctx->link->replay_settings.replay_feature_enabled = true; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_link_setup_replay(ctx->stream, &vrr_params)); +} + +/** + * dm_test_replay_link_setup_success - Verify coasting vtotal configuration + * @test: KUnit test context + * + * When Replay is supported but not yet enabled, amdgpu_dm_link_setup_replay() + * should calculate the link-off frame count and set the coasting vtotal values, + * then return true. + */ +static void dm_test_replay_link_setup_success(struct kunit *test) +{ + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + struct mod_vrr_params vrr_params = { 0 }; + + ctx->link->replay_settings.config.replay_supported = true; + ctx->link->replay_settings.config.replay_version = DC_FREESYNC_REPLAY; + + /* Set timing so calculate_replay_link_off_frame_count computes */ + ctx->stream->timing.v_total = 1125; + ctx->stream->timing.h_total = 2200; + ctx->stream->timing.pix_clk_100hz = 1485000; + ctx->link->dpcd_caps.pr_info.pixel_deviation_per_line = 4; + ctx->link->dpcd_caps.pr_info.max_deviation_line = 10; + + /* min_refresh_in_uhz = 0 makes calc return v_total directly */ + vrr_params.min_refresh_in_uhz = 0; + + KUNIT_EXPECT_TRUE(test, amdgpu_dm_link_setup_replay(ctx->stream, &vrr_params)); + + /* Verify coasting vtotal was set */ + KUNIT_EXPECT_EQ(test, + ctx->link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_NOM], + (uint32_t)1125); + KUNIT_EXPECT_EQ(test, + ctx->link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_STATIC], + (uint32_t)1125); + + /* Verify link_off_frame_count was calculated: 2200*10/(4*1125) = 4 */ + KUNIT_EXPECT_EQ(test, + ctx->link->replay_settings.link_off_frame_count, + (uint32_t)4); +} + +/* Tests for amdgpu_dm_replay_set_event() */ + +/** + * dm_test_replay_set_event_null_stream - Verify NULL stream rejection + * @test: KUnit test context + * + * amdgpu_dm_replay_set_event() should return false when no stream is provided. + */ +static void dm_test_replay_set_event_null_stream(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_replay_set_event(dm, NULL, true, + replay_event_vsync, false)); +} + +/** + * dm_test_replay_set_event_null_link - Verify NULL stream link rejection + * @test: KUnit test context + * + * amdgpu_dm_replay_set_event() should return false when the stream has no + * associated link. + */ +static void dm_test_replay_set_event_null_link(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm); + + ctx->stream->link = NULL; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_replay_set_event(dm, ctx->stream, true, + replay_event_vsync, false)); +} + +/** + * dm_test_replay_set_event_feature_disabled - Verify disabled Replay rejection + * @test: KUnit test context + * + * amdgpu_dm_replay_set_event() should return false when Replay is not enabled + * on the stream link. + */ +static void dm_test_replay_set_event_feature_disabled(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm); + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_replay_set_event(dm, ctx->stream, true, + replay_event_vsync, false)); +} + +/** + * dm_test_replay_set_event_missing_power_module - Verify missing power rejection + * @test: KUnit test context + * + * When Replay is enabled but no power module is available, the event helper + * should return false after failing to read the current Replay events. + */ +static void dm_test_replay_set_event_missing_power_module(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm); + + ctx->link->replay_settings.replay_feature_enabled = true; + + KUNIT_EXPECT_FALSE(test, amdgpu_dm_replay_set_event(dm, ctx->stream, true, + replay_event_vsync, false)); +} + +/** + * dm_test_replay_set_event_already_set - Verify no-op when event already active + * @test: KUnit test context + * + * When the requested event is already in the desired state, the function should + * return true without calling mod_power_set_replay_event(). + */ +static void dm_test_replay_set_event_already_set(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + struct core_power *core_power; + struct power_entity *map; + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm); + + core_power = kunit_kzalloc(test, sizeof(*core_power), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, core_power); + + map = kunit_kzalloc(test, sizeof(*map), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, map); + + /* Wire the power module so mod_power_get_replay_event() succeeds */ + map->stream = ctx->stream; + map->replay_events = replay_event_vsync; + core_power->map = map; + core_power->num_entities = 1; + dm->power_module = &core_power->mod_public; + + ctx->link->replay_settings.replay_feature_enabled = true; + + /* Event already set — should return true without calling set */ + KUNIT_EXPECT_TRUE(test, amdgpu_dm_replay_set_event(dm, ctx->stream, true, + replay_event_vsync, false)); +} + +/** + * dm_test_replay_set_event_already_clear - Verify no-op when event already cleared + * @test: KUnit test context + * + * When clearing an event that is not currently active, the function should + * return true without calling mod_power_set_replay_event(). + */ +static void dm_test_replay_set_event_already_clear(struct kunit *test) +{ + struct amdgpu_display_manager *dm; + struct replay_test_ctx *ctx = alloc_replay_ctx(test); + struct core_power *core_power; + struct power_entity *map; + + dm = kunit_kzalloc(test, sizeof(*dm), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dm); + + core_power = kunit_kzalloc(test, sizeof(*core_power), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, core_power); + + map = kunit_kzalloc(test, sizeof(*map), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, map); + + /* Wire the power module — replay_events has NO vsync bit */ + map->stream = ctx->stream; + map->replay_events = 0; + core_power->map = map; + core_power->num_entities = 1; + dm->power_module = &core_power->mod_public; + + ctx->link->replay_settings.replay_feature_enabled = true; + + /* Clearing an event that's already clear — should return true */ + KUNIT_EXPECT_TRUE(test, amdgpu_dm_replay_set_event(dm, ctx->stream, false, + replay_event_vsync, false)); +} + static struct kunit_case dm_replay_test_cases[] = { + /* amdgpu_dm_link_supports_replay */ KUNIT_CASE(dm_test_replay_supports_all_caps), KUNIT_CASE(dm_test_replay_no_freesync), KUNIT_CASE(dm_test_replay_no_vsdb_replay_mode), @@ -191,6 +590,27 @@ static struct kunit_case dm_replay_test_cases[] = { KUNIT_CASE(dm_test_replay_zero_pixel_deviation), KUNIT_CASE(dm_test_replay_zero_max_deviation_line), KUNIT_CASE(dm_test_replay_both_deviations_zero), + /* amdgpu_dm_set_replay_caps */ + KUNIT_CASE(dm_test_replay_set_caps_already_supported), + KUNIT_CASE(dm_test_replay_set_caps_non_embedded_signal), + KUNIT_CASE(dm_test_replay_set_caps_disallowed_by_panel), + KUNIT_CASE(dm_test_replay_set_caps_link_not_supported), + KUNIT_CASE(dm_test_replay_set_caps_missing_dmub_srv), + KUNIT_CASE(dm_test_replay_set_caps_success), + /* amdgpu_dm_link_setup_replay */ + KUNIT_CASE(dm_test_replay_link_setup_null_stream), + KUNIT_CASE(dm_test_replay_link_setup_null_link), + KUNIT_CASE(dm_test_replay_link_setup_null_vrr_params), + KUNIT_CASE(dm_test_replay_link_setup_not_supported), + KUNIT_CASE(dm_test_replay_link_setup_already_enabled), + KUNIT_CASE(dm_test_replay_link_setup_success), + /* amdgpu_dm_replay_set_event */ + KUNIT_CASE(dm_test_replay_set_event_null_stream), + KUNIT_CASE(dm_test_replay_set_event_null_link), + KUNIT_CASE(dm_test_replay_set_event_feature_disabled), + KUNIT_CASE(dm_test_replay_set_event_missing_power_module), + KUNIT_CASE(dm_test_replay_set_event_already_set), + KUNIT_CASE(dm_test_replay_set_event_already_clear), {} }; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c new file mode 100644 index 000000000000..e48bac7fb024 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_services.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "dm_services.h" +#include "dm_services_types.h" + +/* Tests for dm_get_elapse_time_in_ns() */ + +/** + * dm_test_get_elapse_time_zero_delta - Test Get elapse time zero delta + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_zero_delta(struct kunit *test) +{ + unsigned long long ts = 1000000ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, ts, ts), 0ULL); +} + +/** + * dm_test_get_elapse_time_positive_delta - Test Get elapse time positive delta + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_positive_delta(struct kunit *test) +{ + unsigned long long current_ts = 5000000ULL; + unsigned long long last_ts = 1000000ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, current_ts, last_ts), + 4000000ULL); +} + +/** + * dm_test_get_elapse_time_large_delta - Test Get elapse time large delta + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_large_delta(struct kunit *test) +{ + unsigned long long current_ts = ULLONG_MAX; + unsigned long long last_ts = 0ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, current_ts, last_ts), + ULLONG_MAX); +} + +/** + * dm_test_get_elapse_time_wraparound - Test Get elapse time wraparound + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_wraparound(struct kunit *test) +{ + /* Unsigned wraparound: result = ULLONG_MAX - last + current + 1 */ + unsigned long long current_ts = 5ULL; + unsigned long long last_ts = ULLONG_MAX - 4ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, current_ts, last_ts), + 10ULL); +} + +/* Tests for dm_perf_trace_timestamp() */ + +/** + * dm_test_perf_trace_timestamp_basic - Test Perf trace timestamp basic + * @test: The KUnit test context + * + * The tracepoint is a no-op without an attached probe, so this verifies the + * function dereferences ctx->perf_trace safely and does not crash. + */ +static void dm_test_perf_trace_timestamp_basic(struct kunit *test) +{ + struct dc_context *ctx; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + ctx->perf_trace = kunit_kzalloc(test, sizeof(*ctx->perf_trace), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->perf_trace); + + ctx->perf_trace->read_count = 10; + ctx->perf_trace->write_count = 20; + + dm_perf_trace_timestamp(__func__, __LINE__, ctx); +} + +/* Tests for dm_trace_smu_enter() */ + +/** + * dm_test_trace_smu_enter_null_ctx - Test Trace smu enter null ctx + * @test: The KUnit test context + */ +static void dm_test_trace_smu_enter_null_ctx(struct kunit *test) +{ + /* Empty stub — must not crash with NULL ctx */ + dm_trace_smu_enter(0, 0, 0, NULL); +} + +/** + * dm_test_trace_smu_enter_with_params - Test Trace smu enter with params + * @test: The KUnit test context + */ +static void dm_test_trace_smu_enter_with_params(struct kunit *test) +{ + /* Exercise non-zero msg_id, param_in, and delay */ + dm_trace_smu_enter(0xFF, 0x12345678, 1000, NULL); +} + +/* Tests for dm_trace_smu_exit() */ + +/** + * dm_test_trace_smu_exit_success_null_ctx - Test Trace smu exit success null ctx + * @test: The KUnit test context + */ +static void dm_test_trace_smu_exit_success_null_ctx(struct kunit *test) +{ + /* Empty stub — must not crash on success path with NULL ctx */ + dm_trace_smu_exit(true, 0x0, NULL); +} + +/** + * dm_test_trace_smu_exit_failure_null_ctx - Test Trace smu exit failure null ctx + * @test: The KUnit test context + */ +static void dm_test_trace_smu_exit_failure_null_ctx(struct kunit *test) +{ + /* Empty stub — must not crash on failure path with NULL ctx */ + dm_trace_smu_exit(false, 0x0, NULL); +} + +/** + * dm_test_trace_smu_exit_with_response - Test Trace smu exit with response + * @test: The KUnit test context + */ +static void dm_test_trace_smu_exit_with_response(struct kunit *test) +{ + /* Exercise non-zero response value */ + dm_trace_smu_exit(true, 0xDEADBEEF, NULL); +} + +/* Tests for dm_query_extended_brightness_caps() */ + +/** + * dm_test_query_brightness_caps_null_ctx - Test Query brightness caps null ctx + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_null_ctx(struct kunit *test) +{ + struct dm_acpi_atif_backlight_caps caps = {}; + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(NULL, AcpiDisplayType_LCD1, &caps)); +} + +/** + * dm_test_query_brightness_caps_null_caps - Test Query brightness caps null caps + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_null_caps(struct kunit *test) +{ + struct dc_context ctx = {}; + + ctx.driver_context = (void *)0x1; /* non-NULL sentinel */ + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_LCD1, NULL)); +} + +/** + * dm_test_query_brightness_caps_null_driver_ctx - Test Query brightness caps null driver ctx + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_null_driver_ctx(struct kunit *test) +{ + struct dc_context ctx = {}; + struct dm_acpi_atif_backlight_caps caps = {}; + + ctx.driver_context = NULL; + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_LCD1, &caps)); +} + +/** + * dm_test_query_brightness_caps_lcd2_null_ctx - Test Query brightness caps lcd2 null ctx + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_lcd2_null_ctx(struct kunit *test) +{ + struct dm_acpi_atif_backlight_caps caps = {}; + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(NULL, AcpiDisplayType_LCD2, &caps)); +} + +/** + * dm_test_query_brightness_caps_lcd1_success - Test Query brightness caps lcd1 success + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_lcd1_success(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_dm_backlight_caps *source_caps; + struct dc_context ctx = {}; + struct dm_acpi_atif_backlight_caps caps = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + source_caps = &adev->dm.backlight_caps[0]; + source_caps->caps_valid = true; + source_caps->min_input_signal = 12; + source_caps->max_input_signal = 240; + source_caps->ac_level = 80; + source_caps->dc_level = 40; + source_caps->data_points = 2; + source_caps->luminance_data[0].luminance = 10; + source_caps->luminance_data[0].input_signal = 22; + source_caps->luminance_data[1].luminance = 90; + source_caps->luminance_data[1].input_signal = 200; + ctx.driver_context = adev; + + KUNIT_EXPECT_TRUE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_LCD1, &caps)); + KUNIT_EXPECT_EQ(test, caps.num_data_points, 2); + KUNIT_EXPECT_EQ(test, caps.max_input_signal, 240); + KUNIT_EXPECT_EQ(test, caps.min_input_signal, 12); + KUNIT_EXPECT_EQ(test, caps.ac_level_percentage, 80); + KUNIT_EXPECT_EQ(test, caps.dc_level_percentage, 40); + KUNIT_EXPECT_EQ(test, caps.data_points[0].luminance, 10); + KUNIT_EXPECT_EQ(test, caps.data_points[0].signal_level, 22); + KUNIT_EXPECT_EQ(test, caps.data_points[1].luminance, 90); + KUNIT_EXPECT_EQ(test, caps.data_points[1].signal_level, 200); +} + +/** + * dm_test_query_brightness_caps_non_lcd1_uses_second_slot - Test Query brightness caps non lcd1 uses second slot + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_non_lcd1_uses_second_slot(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_dm_backlight_caps *source_caps; + struct dc_context ctx = {}; + struct dm_acpi_atif_backlight_caps caps = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->dm.backlight_caps[0].caps_valid = true; + adev->dm.backlight_caps[0].min_input_signal = 1; + adev->dm.backlight_caps[0].max_input_signal = 2; + source_caps = &adev->dm.backlight_caps[1]; + source_caps->caps_valid = true; + source_caps->min_input_signal = 33; + source_caps->max_input_signal = 199; + source_caps->ac_level = 70; + source_caps->dc_level = 30; + source_caps->data_points = 0; + ctx.driver_context = adev; + + KUNIT_EXPECT_TRUE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_DFP1, &caps)); + KUNIT_EXPECT_EQ(test, caps.num_data_points, 0); + KUNIT_EXPECT_EQ(test, caps.max_input_signal, 199); + KUNIT_EXPECT_EQ(test, caps.min_input_signal, 33); + KUNIT_EXPECT_EQ(test, caps.ac_level_percentage, 70); + KUNIT_EXPECT_EQ(test, caps.dc_level_percentage, 30); + KUNIT_EXPECT_EQ(test, caps.data_points[0].luminance, 0); + KUNIT_EXPECT_EQ(test, caps.data_points[0].signal_level, 0); +} + +static struct kunit_case amdgpu_dm_services_test_cases[] = { + /* dm_get_elapse_time_in_ns */ + KUNIT_CASE(dm_test_get_elapse_time_zero_delta), + KUNIT_CASE(dm_test_get_elapse_time_positive_delta), + KUNIT_CASE(dm_test_get_elapse_time_large_delta), + KUNIT_CASE(dm_test_get_elapse_time_wraparound), + /* dm_perf_trace_timestamp */ + KUNIT_CASE(dm_test_perf_trace_timestamp_basic), + /* dm_trace_smu_enter */ + KUNIT_CASE(dm_test_trace_smu_enter_null_ctx), + KUNIT_CASE(dm_test_trace_smu_enter_with_params), + /* dm_trace_smu_exit */ + KUNIT_CASE(dm_test_trace_smu_exit_success_null_ctx), + KUNIT_CASE(dm_test_trace_smu_exit_failure_null_ctx), + KUNIT_CASE(dm_test_trace_smu_exit_with_response), + /* dm_query_extended_brightness_caps */ + KUNIT_CASE(dm_test_query_brightness_caps_null_ctx), + KUNIT_CASE(dm_test_query_brightness_caps_null_caps), + KUNIT_CASE(dm_test_query_brightness_caps_null_driver_ctx), + KUNIT_CASE(dm_test_query_brightness_caps_lcd2_null_ctx), + KUNIT_CASE(dm_test_query_brightness_caps_lcd1_success), + KUNIT_CASE(dm_test_query_brightness_caps_non_lcd1_uses_second_slot), + {} +}; + +static struct kunit_suite amdgpu_dm_services_test_suite = { + .name = "amdgpu_dm_services", + .test_cases = amdgpu_dm_services_test_cases, +}; + +kunit_test_suite(amdgpu_dm_services_test_suite); + +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_services"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c new file mode 100644 index 000000000000..0b29bf0a7d04 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c @@ -0,0 +1,949 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include + +#include "dc.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" + +/* Tests for dm_plane_layer_index_cmp() */ + +/** + * dm_test_plane_layer_index_cmp_equal - Test Plane layer index cmp equal + * @test: The KUnit test context + */ +static void dm_test_plane_layer_index_cmp_equal(struct kunit *test) +{ + struct dc_plane_state *plane_a; + struct dc_plane_state *plane_b; + struct dc_surface_update sa, sb; + + plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a); + plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b); + + plane_a->layer_index = 5; + plane_b->layer_index = 5; + sa.surface = plane_a; + sb.surface = plane_b; + + KUNIT_EXPECT_EQ(test, dm_plane_layer_index_cmp(&sa, &sb), 0); +} + +/** + * dm_test_plane_layer_index_cmp_descending - Test Plane layer index cmp descending + * @test: The KUnit test context + */ +static void dm_test_plane_layer_index_cmp_descending(struct kunit *test) +{ + struct dc_plane_state *plane_a; + struct dc_plane_state *plane_b; + struct dc_surface_update sa, sb; + + plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a); + plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b); + + plane_a->layer_index = 3; + plane_b->layer_index = 7; + sa.surface = plane_a; + sb.surface = plane_b; + + /* b has higher index, so cmp(a,b) = b - a > 0 (b sorts first) */ + KUNIT_EXPECT_GT(test, dm_plane_layer_index_cmp(&sa, &sb), 0); +} + +/** + * dm_test_plane_layer_index_cmp_ascending - Test Plane layer index cmp ascending + * @test: The KUnit test context + */ +static void dm_test_plane_layer_index_cmp_ascending(struct kunit *test) +{ + struct dc_plane_state *plane_a; + struct dc_plane_state *plane_b; + struct dc_surface_update sa, sb; + + plane_a = kunit_kzalloc(test, sizeof(*plane_a), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_a); + plane_b = kunit_kzalloc(test, sizeof(*plane_b), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane_b); + + plane_a->layer_index = 9; + plane_b->layer_index = 2; + sa.surface = plane_a; + sb.surface = plane_b; + + /* a has higher index, so cmp(a,b) = b - a < 0 (a sorts first) */ + KUNIT_EXPECT_LT(test, dm_plane_layer_index_cmp(&sa, &sb), 0); +} + +/* Tests for fill_plane_color_attributes() */ + +/** + * dm_test_fill_color_attr_rgb_format - Test Fill color attr rgb format + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_rgb_format(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + /* RGB format: should return 0 and set SRGB regardless of encoding */ + plane_state.color_encoding = DRM_COLOR_YCBCR_BT709; + plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_GRPH_ARGB8888, + &color_space); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, (int)color_space, (int)COLOR_SPACE_SRGB); +} + +/** + * dm_test_fill_color_attr_bt601_full - Test Fill color attr bt601 full + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_bt601_full(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + plane_state.color_encoding = DRM_COLOR_YCBCR_BT601; + plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + &color_space); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, (int)color_space, (int)COLOR_SPACE_YCBCR601); +} + +/** + * dm_test_fill_color_attr_bt601_limited - Test Fill color attr bt601 limited + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_bt601_limited(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + plane_state.color_encoding = DRM_COLOR_YCBCR_BT601; + plane_state.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + &color_space); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, (int)color_space, + (int)COLOR_SPACE_YCBCR601_LIMITED); +} + +/** + * dm_test_fill_color_attr_bt709_full - Test Fill color attr bt709 full + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_bt709_full(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + plane_state.color_encoding = DRM_COLOR_YCBCR_BT709; + plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + &color_space); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, (int)color_space, (int)COLOR_SPACE_YCBCR709); +} + +/** + * dm_test_fill_color_attr_bt709_limited - Test Fill color attr bt709 limited + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_bt709_limited(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + plane_state.color_encoding = DRM_COLOR_YCBCR_BT709; + plane_state.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + &color_space); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, (int)color_space, + (int)COLOR_SPACE_YCBCR709_LIMITED); +} + +/** + * dm_test_fill_color_attr_bt2020_full - Test Fill color attr bt2020 full + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_bt2020_full(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + plane_state.color_encoding = DRM_COLOR_YCBCR_BT2020; + plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + &color_space); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, (int)color_space, + (int)COLOR_SPACE_2020_YCBCR_FULL); +} + +/** + * dm_test_fill_color_attr_bt2020_limited - Test Fill color attr bt2020 limited + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_bt2020_limited(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + plane_state.color_encoding = DRM_COLOR_YCBCR_BT2020; + plane_state.color_range = DRM_COLOR_YCBCR_LIMITED_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + &color_space); + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_EQ(test, (int)color_space, + (int)COLOR_SPACE_2020_YCBCR_LIMITED); +} + +/** + * dm_test_fill_color_attr_invalid_encoding - Test Fill color attr invalid encoding + * @test: The KUnit test context + */ +static void dm_test_fill_color_attr_invalid_encoding(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + enum dc_color_space color_space = COLOR_SPACE_UNKNOWN; + int ret; + + plane_state.color_encoding = 99; + plane_state.color_range = DRM_COLOR_YCBCR_FULL_RANGE; + + ret = fill_plane_color_attributes(&plane_state, + SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr, + &color_space); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +/* Tests for modereset_required() */ + +/** + * dm_test_modereset_required_when_inactive_and_modeset - Test Modereset required when inactive and modeset + * @test: The KUnit test context + */ +static void dm_test_modereset_required_when_inactive_and_modeset(struct kunit *test) +{ + struct drm_crtc_state crtc_state = { 0 }; + + crtc_state.active = false; + crtc_state.mode_changed = true; + + KUNIT_EXPECT_TRUE(test, modereset_required(&crtc_state)); +} + +/** + * dm_test_modereset_not_required_when_active_and_modeset - Test Modereset not required when active and modeset + * @test: The KUnit test context + */ +static void dm_test_modereset_not_required_when_active_and_modeset(struct kunit *test) +{ + struct drm_crtc_state crtc_state = { 0 }; + + crtc_state.active = true; + crtc_state.mode_changed = true; + + KUNIT_EXPECT_FALSE(test, modereset_required(&crtc_state)); +} + +/** + * dm_test_modereset_not_required_when_inactive_without_modeset - Test Modereset not required when inactive without modeset + * @test: The KUnit test context + */ +static void dm_test_modereset_not_required_when_inactive_without_modeset(struct kunit *test) +{ + struct drm_crtc_state crtc_state = { 0 }; + + crtc_state.active = false; + crtc_state.mode_changed = false; + + KUNIT_EXPECT_FALSE(test, modereset_required(&crtc_state)); +} + +/* Tests for dm_get_oriented_plane_size() */ + +/** + * dm_test_oriented_plane_size_rotate_0 - Test Oriented plane size rotate 0 + * @test: The KUnit test context + */ +static void dm_test_oriented_plane_size_rotate_0(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + int src_w = 0; + int src_h = 0; + + plane_state.rotation = DRM_MODE_ROTATE_0; + plane_state.src_w = 1920 << 16; + plane_state.src_h = 1080 << 16; + + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); + + KUNIT_EXPECT_EQ(test, src_w, 1920); + KUNIT_EXPECT_EQ(test, src_h, 1080); +} + +/** + * dm_test_oriented_plane_size_rotate_90 - Test Oriented plane size rotate 90 + * @test: The KUnit test context + */ +static void dm_test_oriented_plane_size_rotate_90(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + int src_w = 0; + int src_h = 0; + + plane_state.rotation = DRM_MODE_ROTATE_90; + plane_state.src_w = 1920 << 16; + plane_state.src_h = 1080 << 16; + + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); + + KUNIT_EXPECT_EQ(test, src_w, 1080); + KUNIT_EXPECT_EQ(test, src_h, 1920); +} + +/** + * dm_test_oriented_plane_size_rotate_180 - Test Oriented plane size rotate 180 + * @test: The KUnit test context + */ +static void dm_test_oriented_plane_size_rotate_180(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + int src_w = 0; + int src_h = 0; + + plane_state.rotation = DRM_MODE_ROTATE_180; + plane_state.src_w = 1920 << 16; + plane_state.src_h = 1080 << 16; + + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); + + KUNIT_EXPECT_EQ(test, src_w, 1920); + KUNIT_EXPECT_EQ(test, src_h, 1080); +} + +/** + * dm_test_oriented_plane_size_rotate_270 - Test Oriented plane size rotate 270 + * @test: The KUnit test context + */ +static void dm_test_oriented_plane_size_rotate_270(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + int src_w = 0; + int src_h = 0; + + plane_state.rotation = DRM_MODE_ROTATE_270; + plane_state.src_w = 1920 << 16; + plane_state.src_h = 1080 << 16; + + dm_get_oriented_plane_size(&plane_state, &src_w, &src_h); + + KUNIT_EXPECT_EQ(test, src_w, 1080); + KUNIT_EXPECT_EQ(test, src_h, 1920); +} + +/* Tests for dm_get_plane_scale() */ + +/** + * dm_test_get_plane_scale_identity - Test Get plane scale identity + * @test: The KUnit test context + */ +static void dm_test_get_plane_scale_identity(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + int scale_w = 0; + int scale_h = 0; + + plane_state.rotation = DRM_MODE_ROTATE_0; + plane_state.src_w = 1920 << 16; + plane_state.src_h = 1080 << 16; + plane_state.crtc_w = 1920; + plane_state.crtc_h = 1080; + + dm_get_plane_scale(&plane_state, &scale_w, &scale_h); + + KUNIT_EXPECT_EQ(test, scale_w, 1000); + KUNIT_EXPECT_EQ(test, scale_h, 1000); +} + +/** + * dm_test_get_plane_scale_rotate_90_identity - Test Get plane scale rotate 90 identity + * @test: The KUnit test context + */ +static void dm_test_get_plane_scale_rotate_90_identity(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + int scale_w = 0; + int scale_h = 0; + + plane_state.rotation = DRM_MODE_ROTATE_90; + plane_state.src_w = 1920 << 16; + plane_state.src_h = 1080 << 16; + plane_state.crtc_w = 1080; + plane_state.crtc_h = 1920; + + dm_get_plane_scale(&plane_state, &scale_w, &scale_h); + + KUNIT_EXPECT_EQ(test, scale_w, 1000); + KUNIT_EXPECT_EQ(test, scale_h, 1000); +} + +/** + * dm_test_get_plane_scale_zero_src_width - Test Get plane scale zero src width + * @test: The KUnit test context + */ +static void dm_test_get_plane_scale_zero_src_width(struct kunit *test) +{ + struct drm_plane_state plane_state = { 0 }; + int scale_w = 0; + int scale_h = 0; + + plane_state.rotation = DRM_MODE_ROTATE_0; + plane_state.src_w = 0; + plane_state.src_h = 1080 << 16; + plane_state.crtc_w = 100; + plane_state.crtc_h = 200; + + dm_get_plane_scale(&plane_state, &scale_w, &scale_h); + + KUNIT_EXPECT_EQ(test, scale_w, 0); + KUNIT_EXPECT_EQ(test, scale_h, 185); +} + +/* Tests for is_scaling_state_different() */ + +/** + * dm_test_scaling_state_same - Test identical scaling states compare equal + * @test: The KUnit test context + */ +static void dm_test_scaling_state_same(struct kunit *test) +{ + struct dm_connector_state *a; + struct dm_connector_state *b; + + a = kunit_kzalloc(test, sizeof(*a), GFP_KERNEL); + b = kunit_kzalloc(test, sizeof(*b), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, a); + KUNIT_ASSERT_NOT_NULL(test, b); + + a->scaling = RMX_FULL; + a->underscan_enable = false; + *b = *a; + + KUNIT_EXPECT_FALSE(test, is_scaling_state_different(a, b)); +} + +/** + * dm_test_scaling_state_scaling_changed - Test differing scaling mode is detected + * @test: The KUnit test context + */ +static void dm_test_scaling_state_scaling_changed(struct kunit *test) +{ + struct dm_connector_state *a; + struct dm_connector_state *b; + + a = kunit_kzalloc(test, sizeof(*a), GFP_KERNEL); + b = kunit_kzalloc(test, sizeof(*b), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, a); + KUNIT_ASSERT_NOT_NULL(test, b); + + a->scaling = RMX_FULL; + b->scaling = RMX_CENTER; + + KUNIT_EXPECT_TRUE(test, is_scaling_state_different(a, b)); +} + +/** + * dm_test_scaling_state_underscan_enabled - Test enabling underscan with borders differs + * @test: The KUnit test context + */ +static void dm_test_scaling_state_underscan_enabled(struct kunit *test) +{ + struct dm_connector_state *old_state; + struct dm_connector_state *new_state; + + old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); + new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, old_state); + KUNIT_ASSERT_NOT_NULL(test, new_state); + + /* new enables underscan with non-zero borders, old has it disabled */ + new_state->underscan_enable = true; + new_state->underscan_hborder = 16; + new_state->underscan_vborder = 16; + old_state->underscan_enable = false; + + KUNIT_EXPECT_TRUE(test, is_scaling_state_different(new_state, old_state)); +} + +/** + * dm_test_scaling_state_underscan_border_changed - Test changed underscan borders differ + * @test: The KUnit test context + */ +static void dm_test_scaling_state_underscan_border_changed(struct kunit *test) +{ + struct dm_connector_state *a; + struct dm_connector_state *b; + + a = kunit_kzalloc(test, sizeof(*a), GFP_KERNEL); + b = kunit_kzalloc(test, sizeof(*b), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, a); + KUNIT_ASSERT_NOT_NULL(test, b); + + a->underscan_enable = true; + a->underscan_hborder = 16; + a->underscan_vborder = 16; + *b = *a; + b->underscan_hborder = 32; + + KUNIT_EXPECT_TRUE(test, is_scaling_state_different(a, b)); +} + +/* Tests for is_timing_unchanged_for_freesync() */ + +/** + * dm_test_timing_unchanged_null_args - Test NULL crtc states return false + * @test: The KUnit test context + */ +static void dm_test_timing_unchanged_null_args(struct kunit *test) +{ + struct drm_crtc_state crtc_state = { 0 }; + + KUNIT_EXPECT_FALSE(test, + is_timing_unchanged_for_freesync(NULL, &crtc_state)); + KUNIT_EXPECT_FALSE(test, + is_timing_unchanged_for_freesync(&crtc_state, NULL)); +} + +/** + * dm_test_timing_unchanged_identical_modes - Test identical modes are not "unchanged" + * @test: The KUnit test context + * + * The helper only returns true when vtotal/vsync shift (vrr) while the rest + * of the timing stays fixed, so identical modes must return false. + */ +static void dm_test_timing_unchanged_identical_modes(struct kunit *test) +{ + struct drm_crtc_state old_state = { 0 }; + struct drm_crtc_state new_state = { 0 }; + + old_state.mode.clock = 148500; + old_state.mode.hdisplay = 1920; + old_state.mode.vdisplay = 1080; + old_state.mode.htotal = 2200; + old_state.mode.vtotal = 1125; + new_state.mode = old_state.mode; + + KUNIT_EXPECT_FALSE(test, + is_timing_unchanged_for_freesync(&old_state, &new_state)); +} + +/** + * dm_test_timing_unchanged_vrr_shift - Test vrr-style vtotal/vsync shift is detected + * @test: The KUnit test context + */ +static void dm_test_timing_unchanged_vrr_shift(struct kunit *test) +{ + struct drm_crtc_state old_state = { 0 }; + struct drm_crtc_state new_state = { 0 }; + + old_state.mode.clock = 148500; + old_state.mode.hdisplay = 1920; + old_state.mode.vdisplay = 1080; + old_state.mode.htotal = 2200; + old_state.mode.vtotal = 1125; + old_state.mode.hsync_start = 2008; + old_state.mode.vsync_start = 1084; + old_state.mode.hsync_end = 2052; + old_state.mode.vsync_end = 1089; + + /* Same horizontal timing, vertical totals/sync shifted by 125 lines */ + new_state.mode = old_state.mode; + new_state.mode.vtotal = 1250; + new_state.mode.vsync_start = 1209; + new_state.mode.vsync_end = 1214; + + KUNIT_EXPECT_TRUE(test, + is_timing_unchanged_for_freesync(&old_state, &new_state)); +} + +/** + * dm_test_timing_unchanged_clock_changed - Test pixel clock change returns false + * @test: The KUnit test context + */ +static void dm_test_timing_unchanged_clock_changed(struct kunit *test) +{ + struct drm_crtc_state old_state = { 0 }; + struct drm_crtc_state new_state = { 0 }; + + old_state.mode.clock = 148500; + old_state.mode.htotal = 2200; + old_state.mode.vtotal = 1125; + old_state.mode.vsync_start = 1084; + old_state.mode.vsync_end = 1089; + + new_state.mode = old_state.mode; + new_state.mode.clock = 297000; + new_state.mode.vtotal = 1250; + new_state.mode.vsync_start = 1209; + new_state.mode.vsync_end = 1214; + + KUNIT_EXPECT_FALSE(test, + is_timing_unchanged_for_freesync(&old_state, &new_state)); +} + +/* Tests for set_freesync_fixed_config() */ + +/** + * dm_test_set_freesync_fixed_config_60hz - Test fixed refresh computed for 1080p60 + * @test: The KUnit test context + */ +static void dm_test_set_freesync_fixed_config_60hz(struct kunit *test) +{ + struct dm_crtc_state dm_crtc_state = { 0 }; + + dm_crtc_state.base.mode.clock = 148500; + dm_crtc_state.base.mode.htotal = 2200; + dm_crtc_state.base.mode.vtotal = 1125; + + set_freesync_fixed_config(&dm_crtc_state); + + KUNIT_EXPECT_EQ(test, (int)dm_crtc_state.freesync_config.state, + (int)VRR_STATE_ACTIVE_FIXED); + /* 148500 kHz / (2200 * 1125) = 60 Hz = 60000000 uHz */ + KUNIT_EXPECT_EQ(test, dm_crtc_state.freesync_config.fixed_refresh_in_uhz, + 60000000U); +} + +/* Tests for is_dc_timing_adjust_needed() */ + +/** + * dm_test_dc_timing_adjust_pending - Test a pending hw timing adjust forces true + * @test: The KUnit test context + */ +static void dm_test_dc_timing_adjust_pending(struct kunit *test) +{ + struct dm_crtc_state *old_state, *new_state; + struct dc_stream_state *stream; + + old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + + new_state->stream = stream; + stream->adjust.timing_adjust_pending = 1; + + KUNIT_EXPECT_TRUE(test, is_dc_timing_adjust_needed(old_state, new_state)); +} + +/** + * dm_test_dc_timing_adjust_active_fixed - Test VRR active-fixed forces true + * @test: The KUnit test context + */ +static void dm_test_dc_timing_adjust_active_fixed(struct kunit *test) +{ + struct dm_crtc_state *old_state, *new_state; + struct dc_stream_state *stream; + + old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + + new_state->stream = stream; + new_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED; + + KUNIT_EXPECT_TRUE(test, is_dc_timing_adjust_needed(old_state, new_state)); +} + +/** + * dm_test_dc_timing_adjust_vrr_toggle - Test a change in vrr active state forces true + * @test: The KUnit test context + */ +static void dm_test_dc_timing_adjust_vrr_toggle(struct kunit *test) +{ + struct dm_crtc_state *old_state, *new_state; + struct dc_stream_state *stream; + + old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + + new_state->stream = stream; + old_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE; + new_state->freesync_config.state = VRR_STATE_INACTIVE; + + KUNIT_EXPECT_TRUE(test, is_dc_timing_adjust_needed(old_state, new_state)); +} + +/** + * dm_test_dc_timing_adjust_not_needed - Test steady-state timing needs no adjust + * @test: The KUnit test context + */ +static void dm_test_dc_timing_adjust_not_needed(struct kunit *test) +{ + struct dm_crtc_state *old_state, *new_state; + struct dc_stream_state *stream; + + old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state); + new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state); + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + + new_state->stream = stream; + old_state->freesync_config.state = VRR_STATE_INACTIVE; + new_state->freesync_config.state = VRR_STATE_INACTIVE; + + KUNIT_EXPECT_FALSE(test, is_dc_timing_adjust_needed(old_state, new_state)); +} + +/* Tests for set_multisync_trigger_params() */ + +/** + * dm_test_multisync_trigger_disabled - Test disabled reset leaves params untouched + * @test: The KUnit test context + */ +static void dm_test_multisync_trigger_disabled(struct kunit *test) +{ + struct dc_stream_state *stream; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + + stream->triggered_crtc_reset.enabled = false; + stream->triggered_crtc_reset.event = CRTC_EVENT_VSYNC_FALLING; + stream->triggered_crtc_reset.delay = TRIGGER_DELAY_NEXT_LINE; + + set_multisync_trigger_params(stream); + + /* Nothing should change when the reset trigger is disabled */ + KUNIT_EXPECT_EQ(test, (int)stream->triggered_crtc_reset.event, + (int)CRTC_EVENT_VSYNC_FALLING); + KUNIT_EXPECT_EQ(test, (int)stream->triggered_crtc_reset.delay, + (int)TRIGGER_DELAY_NEXT_LINE); +} + +/** + * dm_test_multisync_trigger_rising - Test positive vsync polarity selects rising edge + * @test: The KUnit test context + */ +static void dm_test_multisync_trigger_rising(struct kunit *test) +{ + struct dc_stream_state *stream; + struct dc_stream_state *master; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + master = kunit_kzalloc(test, sizeof(*master), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, master); + + master->timing.flags.VSYNC_POSITIVE_POLARITY = 1; + stream->triggered_crtc_reset.enabled = true; + stream->triggered_crtc_reset.event_source = master; + + set_multisync_trigger_params(stream); + + KUNIT_EXPECT_EQ(test, (int)stream->triggered_crtc_reset.event, + (int)CRTC_EVENT_VSYNC_RISING); + KUNIT_EXPECT_EQ(test, (int)stream->triggered_crtc_reset.delay, + (int)TRIGGER_DELAY_NEXT_PIXEL); +} + +/** + * dm_test_multisync_trigger_falling - Test negative vsync polarity selects falling edge + * @test: The KUnit test context + */ +static void dm_test_multisync_trigger_falling(struct kunit *test) +{ + struct dc_stream_state *stream; + struct dc_stream_state *master; + + stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); + master = kunit_kzalloc(test, sizeof(*master), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, master); + + master->timing.flags.VSYNC_POSITIVE_POLARITY = 0; + stream->triggered_crtc_reset.enabled = true; + stream->triggered_crtc_reset.event_source = master; + + set_multisync_trigger_params(stream); + + KUNIT_EXPECT_EQ(test, (int)stream->triggered_crtc_reset.event, + (int)CRTC_EVENT_VSYNC_FALLING); + KUNIT_EXPECT_EQ(test, (int)stream->triggered_crtc_reset.delay, + (int)TRIGGER_DELAY_NEXT_PIXEL); +} + +/* Tests for set_master_stream() */ + +/** + * dm_test_master_stream_highest_refresh - Test highest refresh-rate stream becomes master + * @test: The KUnit test context + */ +static void dm_test_master_stream_highest_refresh(struct kunit *test) +{ + struct dc_stream_state *stream0, *stream1; + struct dc_stream_state *stream_set[2]; + + stream0 = kunit_kzalloc(test, sizeof(*stream0), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream0); + stream1 = kunit_kzalloc(test, sizeof(*stream1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream1); + stream_set[0] = stream0; + stream_set[1] = stream1; + + /* stream0: 60Hz, stream1: 120Hz -> stream1 is master */ + stream0->triggered_crtc_reset.enabled = true; + stream0->timing.pix_clk_100hz = 1485000; + stream0->timing.h_total = 2200; + stream0->timing.v_total = 1125; + + stream1->triggered_crtc_reset.enabled = true; + stream1->timing.pix_clk_100hz = 2970000; + stream1->timing.h_total = 2200; + stream1->timing.v_total = 1125; + + set_master_stream(stream_set, 2); + + KUNIT_EXPECT_PTR_EQ(test, stream0->triggered_crtc_reset.event_source, + stream1); + KUNIT_EXPECT_PTR_EQ(test, stream1->triggered_crtc_reset.event_source, + stream1); +} + +/** + * dm_test_master_stream_defaults_to_first - Test default master when none triggered + * @test: The KUnit test context + * + * When no stream has the reset trigger enabled, master_stream stays 0 and all + * streams point at the first stream as their event source. + */ +static void dm_test_master_stream_defaults_to_first(struct kunit *test) +{ + struct dc_stream_state *stream0, *stream1; + struct dc_stream_state *stream_set[2]; + + stream0 = kunit_kzalloc(test, sizeof(*stream0), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream0); + stream1 = kunit_kzalloc(test, sizeof(*stream1), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream1); + stream_set[0] = stream0; + stream_set[1] = stream1; + + set_master_stream(stream_set, 2); + + KUNIT_EXPECT_PTR_EQ(test, stream0->triggered_crtc_reset.event_source, + stream0); + KUNIT_EXPECT_PTR_EQ(test, stream1->triggered_crtc_reset.event_source, + stream0); +} + +static struct kunit_case amdgpu_dm_tests[] = { + /* dm_plane_layer_index_cmp */ + KUNIT_CASE(dm_test_plane_layer_index_cmp_equal), + KUNIT_CASE(dm_test_plane_layer_index_cmp_descending), + KUNIT_CASE(dm_test_plane_layer_index_cmp_ascending), + /* fill_plane_color_attributes */ + KUNIT_CASE(dm_test_fill_color_attr_rgb_format), + KUNIT_CASE(dm_test_fill_color_attr_bt601_full), + KUNIT_CASE(dm_test_fill_color_attr_bt601_limited), + KUNIT_CASE(dm_test_fill_color_attr_bt709_full), + KUNIT_CASE(dm_test_fill_color_attr_bt709_limited), + KUNIT_CASE(dm_test_fill_color_attr_bt2020_full), + KUNIT_CASE(dm_test_fill_color_attr_bt2020_limited), + KUNIT_CASE(dm_test_fill_color_attr_invalid_encoding), + /* modereset_required */ + KUNIT_CASE(dm_test_modereset_required_when_inactive_and_modeset), + KUNIT_CASE(dm_test_modereset_not_required_when_active_and_modeset), + KUNIT_CASE(dm_test_modereset_not_required_when_inactive_without_modeset), + /* dm_get_oriented_plane_size */ + KUNIT_CASE(dm_test_oriented_plane_size_rotate_0), + KUNIT_CASE(dm_test_oriented_plane_size_rotate_90), + KUNIT_CASE(dm_test_oriented_plane_size_rotate_180), + KUNIT_CASE(dm_test_oriented_plane_size_rotate_270), + /* dm_get_plane_scale */ + KUNIT_CASE(dm_test_get_plane_scale_identity), + KUNIT_CASE(dm_test_get_plane_scale_rotate_90_identity), + KUNIT_CASE(dm_test_get_plane_scale_zero_src_width), + /* is_scaling_state_different */ + KUNIT_CASE(dm_test_scaling_state_same), + KUNIT_CASE(dm_test_scaling_state_scaling_changed), + KUNIT_CASE(dm_test_scaling_state_underscan_enabled), + KUNIT_CASE(dm_test_scaling_state_underscan_border_changed), + /* is_timing_unchanged_for_freesync */ + KUNIT_CASE(dm_test_timing_unchanged_null_args), + KUNIT_CASE(dm_test_timing_unchanged_identical_modes), + KUNIT_CASE(dm_test_timing_unchanged_vrr_shift), + KUNIT_CASE(dm_test_timing_unchanged_clock_changed), + /* set_freesync_fixed_config */ + KUNIT_CASE(dm_test_set_freesync_fixed_config_60hz), + /* is_dc_timing_adjust_needed */ + KUNIT_CASE(dm_test_dc_timing_adjust_pending), + KUNIT_CASE(dm_test_dc_timing_adjust_active_fixed), + KUNIT_CASE(dm_test_dc_timing_adjust_vrr_toggle), + KUNIT_CASE(dm_test_dc_timing_adjust_not_needed), + /* set_multisync_trigger_params */ + KUNIT_CASE(dm_test_multisync_trigger_disabled), + KUNIT_CASE(dm_test_multisync_trigger_rising), + KUNIT_CASE(dm_test_multisync_trigger_falling), + /* set_master_stream */ + KUNIT_CASE(dm_test_master_stream_highest_refresh), + KUNIT_CASE(dm_test_master_stream_defaults_to_first), + {} +}; + +static struct kunit_suite amdgpu_dm_test_suite = { + .name = "amdgpu_dm", + .test_cases = amdgpu_dm_tests, +}; + +kunit_test_suite(amdgpu_dm_test_suite); + +MODULE_AUTHOR("AMD"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm"); +MODULE_LICENSE("Dual MIT/GPL"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c new file mode 100644 index 000000000000..c71f61a2438d --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_wb_test.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_wb.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_dm.h" +#include "amdgpu_dm_wb.h" +#include "amdgpu_dm_kunit_test_helpers.h" + + +/* Helper functions */ + +static struct drm_crtc_state *alloc_test_crtc_state(struct kunit *test, + int hdisplay, int vdisplay) +{ + struct drm_crtc_state *crtc_state; + + crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, crtc_state); + + crtc_state->mode.hdisplay = hdisplay; + crtc_state->mode.vdisplay = vdisplay; + + return crtc_state; +} + +static struct drm_connector_state *alloc_test_conn_state(struct kunit *test, + int fb_width, + int fb_height, + u32 format) +{ + struct drm_connector_state *conn_state; + struct drm_writeback_job *job; + struct drm_framebuffer *fb; + struct drm_format_info *fmt_info; + + conn_state = kunit_kzalloc(test, sizeof(*conn_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + job = kunit_kzalloc(test, sizeof(*job), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, job); + + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fb); + + fmt_info = kunit_kzalloc(test, sizeof(*fmt_info), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, fmt_info); + + fb->width = fb_width; + fb->height = fb_height; + fmt_info->format = format; + fb->format = fmt_info; + + job->fb = fb; + conn_state->writeback_job = job; + + return conn_state; +} + + + +/* Tests for amdgpu_dm_wb_encoder_atomic_check */ + +/** + * dm_test_wb_atomic_check_no_job - Verify early return when no writeback job + * @test: KUnit test context + * + * When conn_state->writeback_job is NULL, no writeback is requested and the + * function should return 0 without further validation. + */ +static void dm_test_wb_atomic_check_no_job(struct kunit *test) +{ + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + int ret; + + crtc_state = alloc_test_crtc_state(test, 1920, 1080); + conn_state = kunit_kzalloc(test, sizeof(*conn_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + /* No writeback_job — should return 0 */ + conn_state->writeback_job = NULL; + ret = amdgpu_dm_wb_encoder_atomic_check(NULL, crtc_state, conn_state); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +/** + * dm_test_wb_atomic_check_no_fb - Verify early return when job has no framebuffer + * @test: KUnit test context + * + * When a writeback job exists but job->fb is NULL, the function should return 0 + * without validating dimensions or pixel format. + */ +static void dm_test_wb_atomic_check_no_fb(struct kunit *test) +{ + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + struct drm_writeback_job *job; + int ret; + + crtc_state = alloc_test_crtc_state(test, 1920, 1080); + conn_state = kunit_kzalloc(test, sizeof(*conn_state), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, conn_state); + + job = kunit_kzalloc(test, sizeof(*job), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, job); + + /* writeback_job exists but no fb — should return 0 */ + job->fb = NULL; + conn_state->writeback_job = job; + ret = amdgpu_dm_wb_encoder_atomic_check(NULL, crtc_state, conn_state); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +/** + * dm_test_wb_atomic_check_valid - Verify success with matching size and supported format + * @test: KUnit test context + * + * When the framebuffer dimensions match the CRTC mode and the pixel format is + * in the supported formats list, the function should return 0. + */ +static void dm_test_wb_atomic_check_valid(struct kunit *test) +{ + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + int ret; + + crtc_state = alloc_test_crtc_state(test, 1920, 1080); + conn_state = alloc_test_conn_state(test, 1920, 1080, + DRM_FORMAT_XRGB2101010); + + ret = amdgpu_dm_wb_encoder_atomic_check(NULL, crtc_state, conn_state); + KUNIT_EXPECT_EQ(test, ret, 0); +} + +/** + * dm_test_wb_atomic_check_size_mismatch - Verify rejection when both dimensions differ + * @test: KUnit test context + * + * When both framebuffer width and height differ from the CRTC mode, the + * function should return -EINVAL. + */ +static void dm_test_wb_atomic_check_size_mismatch(struct kunit *test) +{ + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + int ret; + + /* FB is 3840x2160 but mode is 1920x1080 */ + crtc_state = alloc_test_crtc_state(test, 1920, 1080); + conn_state = alloc_test_conn_state(test, 3840, 2160, + DRM_FORMAT_XRGB2101010); + + ret = amdgpu_dm_wb_encoder_atomic_check(NULL, crtc_state, conn_state); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +/** + * dm_test_wb_atomic_check_width_mismatch - Verify rejection when width alone differs + * @test: KUnit test context + * + * When only the framebuffer width differs from the CRTC mode hdisplay, the + * function should return -EINVAL. + */ +static void dm_test_wb_atomic_check_width_mismatch(struct kunit *test) +{ + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + int ret; + + /* Width doesn't match */ + crtc_state = alloc_test_crtc_state(test, 1920, 1080); + conn_state = alloc_test_conn_state(test, 1280, 1080, + DRM_FORMAT_XRGB2101010); + + ret = amdgpu_dm_wb_encoder_atomic_check(NULL, crtc_state, conn_state); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +/** + * dm_test_wb_atomic_check_height_mismatch - Verify rejection when height alone differs + * @test: KUnit test context + * + * When only the framebuffer height differs from the CRTC mode vdisplay, the + * function should return -EINVAL. + */ +static void dm_test_wb_atomic_check_height_mismatch(struct kunit *test) +{ + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + int ret; + + /* Height doesn't match */ + crtc_state = alloc_test_crtc_state(test, 1920, 1080); + conn_state = alloc_test_conn_state(test, 1920, 720, + DRM_FORMAT_XRGB2101010); + + ret = amdgpu_dm_wb_encoder_atomic_check(NULL, crtc_state, conn_state); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +/** + * dm_test_wb_atomic_check_invalid_format - Verify rejection of unsupported pixel format + * @test: KUnit test context + * + * When the framebuffer dimensions match but the pixel format is not in + * amdgpu_dm_wb_formats[], the function should return -EINVAL. + */ +static void dm_test_wb_atomic_check_invalid_format(struct kunit *test) +{ + struct drm_crtc_state *crtc_state; + struct drm_connector_state *conn_state; + int ret; + + /* Correct size but unsupported format */ + crtc_state = alloc_test_crtc_state(test, 1920, 1080); + conn_state = alloc_test_conn_state(test, 1920, 1080, + DRM_FORMAT_XRGB8888); + + ret = amdgpu_dm_wb_encoder_atomic_check(NULL, crtc_state, conn_state); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); +} + +/* Tests for amdgpu_dm_wb_connector_get_modes using DRM mock */ + +static const struct drm_connector_funcs dm_wb_test_connector_funcs = { + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .reset = drm_atomic_helper_connector_reset, +}; + +/** + * dm_test_wb_get_modes_returns_modes - Verify at least one mode is returned + * @test: KUnit test context + * + * Uses a DRM mock connector to verify that amdgpu_dm_wb_connector_get_modes() + * populates the connector with at least one display mode. + */ +static void dm_test_wb_get_modes_returns_modes(struct kunit *test) +{ + struct device *dev; + struct drm_device *drm; + struct drm_connector *connector; + int count; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(*drm), 0, + DRIVER_MODESET | DRIVER_ATOMIC); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, connector); + + drmm_connector_init(drm, connector, &dm_wb_test_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL, NULL); + + count = amdgpu_dm_wb_connector_get_modes(connector); + + /* drm_add_modes_noedid should return at least one mode */ + KUNIT_EXPECT_GT(test, count, 0); +} + +/** + * dm_test_wb_get_modes_bounded_by_max - Verify all modes are within max resolution + * @test: KUnit test context + * + * Uses a DRM mock connector to verify that all modes returned by + * amdgpu_dm_wb_connector_get_modes() have hdisplay <= 3840 and + * vdisplay <= 2160, matching the DWB hardware maximum. + */ +static void dm_test_wb_get_modes_bounded_by_max(struct kunit *test) +{ + struct device *dev; + struct drm_device *drm; + struct drm_connector *connector; + struct drm_display_mode *mode; + + dev = drm_kunit_helper_alloc_device(test); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + drm = __drm_kunit_helper_alloc_drm_device(test, dev, + sizeof(*drm), 0, + DRIVER_MODESET | DRIVER_ATOMIC); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, connector); + + drmm_connector_init(drm, connector, &dm_wb_test_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL, NULL); + + amdgpu_dm_wb_connector_get_modes(connector); + + /* All modes must fit within 3840x2160 */ + list_for_each_entry(mode, &connector->probed_modes, head) { + KUNIT_EXPECT_LE(test, mode->hdisplay, 3840); + KUNIT_EXPECT_LE(test, mode->vdisplay, 2160); + } +} + +/* Tests for amdgpu_dm_wb_connector_init using DRM mock */ + +/** + * dm_test_wb_connector_init_success - Verify writeback connector initialization + * @test: KUnit test context + * + * Uses a DRM mock device embedded in struct amdgpu_device to verify that + * amdgpu_dm_wb_connector_init() initializes the writeback connector, stores + * the DC link, installs connector state through reset, and wires the expected + * DRM callbacks. + */ +static void dm_test_wb_connector_init_success(struct kunit *test) +{ + struct amdgpu_dm_wb_connector *wbcon; + struct amdgpu_display_manager *dm; + struct amdgpu_device *adev; + struct dc_link *link; + struct dc *dc; + int ret; + + adev = dm_kunit_alloc_adev(test); + adev->mode_info.num_crtc = 1; + dm = &adev->dm; + dm->adev = adev; + + dc = kunit_kzalloc(test, sizeof(*dc), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, dc); + + link = kunit_kzalloc(test, sizeof(*link), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, link); + + dc->links[0] = link; + dm->dc = dc; + + wbcon = kunit_kzalloc(test, sizeof(*wbcon), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, wbcon); + + ret = amdgpu_dm_wb_connector_init(dm, wbcon, 0); + + KUNIT_EXPECT_EQ(test, ret, 0); + KUNIT_EXPECT_PTR_EQ(test, wbcon->link, link); + KUNIT_EXPECT_TRUE(test, wbcon->base.base.funcs != NULL); + KUNIT_EXPECT_TRUE(test, wbcon->base.base.helper_private != NULL); + KUNIT_EXPECT_TRUE(test, wbcon->base.base.state != NULL); + KUNIT_EXPECT_TRUE(test, wbcon->base.encoder.funcs != NULL); + KUNIT_EXPECT_EQ(test, wbcon->base.encoder.possible_crtcs, 0x1); +} + +static struct kunit_case dm_wb_test_cases[] = { + /* amdgpu_dm_wb_encoder_atomic_check */ + KUNIT_CASE(dm_test_wb_atomic_check_no_job), + KUNIT_CASE(dm_test_wb_atomic_check_no_fb), + KUNIT_CASE(dm_test_wb_atomic_check_valid), + KUNIT_CASE(dm_test_wb_atomic_check_size_mismatch), + KUNIT_CASE(dm_test_wb_atomic_check_width_mismatch), + KUNIT_CASE(dm_test_wb_atomic_check_height_mismatch), + KUNIT_CASE(dm_test_wb_atomic_check_invalid_format), + /* amdgpu_dm_wb_connector_get_modes */ + KUNIT_CASE(dm_test_wb_get_modes_returns_modes), + KUNIT_CASE(dm_test_wb_get_modes_bounded_by_max), + /* amdgpu_dm_wb_connector_init */ + KUNIT_CASE(dm_test_wb_connector_init_success), + {} +}; + +static struct kunit_suite dm_wb_test_suite = { + .name = "amdgpu_dm_wb", + .test_cases = dm_wb_test_cases, +}; + +kunit_test_suite(dm_wb_test_suite); + +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_wb"); diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c index 4a60c5f54a04..6ee3da89d058 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c @@ -10,6 +10,7 @@ #include "dcn31/dcn31_clk_mgr.h" #include "dcn32/dcn32_clk_mgr.h" #include "dcn401/dcn401_clk_mgr.h" +#include "hw_sequencer.h" #include "reg_helper.h" #include "core_types.h" #include "dm_helpers.h" @@ -1085,7 +1086,8 @@ static unsigned int dcn401_build_update_display_clocks_sequence( struct clk_mgr *clk_mgr_base, struct dc_state *context, struct dc_clocks *new_clocks, - bool safe_to_lower) + bool safe_to_lower, + unsigned int num_steps_start) { struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); @@ -1100,7 +1102,7 @@ static unsigned int dcn401_build_update_display_clocks_sequence( bool frl_present = false; unsigned int i; - unsigned int num_steps = 0; + unsigned int num_steps = num_steps_start; /* CLK_MGR401_READ_CLOCKS_FROM_DENTIST */ if (clk_mgr_base->clks.dispclk_khz == 0 || @@ -1239,6 +1241,44 @@ static unsigned int dcn401_build_update_display_clocks_sequence( return num_steps; } +/* + * Build-for-BLS functions. + * These build both bandwidth and display clock sequences into the clk_mgr's + * internal block sequence array, then add a single CLK_MGR_UPDATE_CLOCKS step + * to the HWSS block sequence whose executor will call + * execute_clk_mgr_block_sequence to dispatch all accumulated steps. + */ +void dcn401_build_clock_update_for_bls( + struct clk_mgr *clk_mgr_base, + struct dc_state *context, + bool safe_to_lower, + struct block_sequence_state *seq_state) +{ + struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); + unsigned int num_bw_steps; + unsigned int total_steps; + + /* Build bandwidth clocks sequence starting at index 0 */ + num_bw_steps = dcn401_build_update_bandwidth_clocks_sequence(clk_mgr_base, + context, + &context->bw_ctx.bw.dcn.clk, + safe_to_lower); + + /* Build display clocks sequence appended after bandwidth steps */ + total_steps = dcn401_build_update_display_clocks_sequence(clk_mgr_base, + context, + &context->bw_ctx.bw.dcn.clk, + safe_to_lower, + num_bw_steps); + + /* Store total step count for the executor */ + clk_mgr401->num_block_sequence_steps = total_steps; + + /* Add single HWSS step that will execute all clk_mgr block sequence steps */ + hwss_add_clk_mgr_update_clocks(seq_state, clk_mgr_base); +} + static void dcn401_update_clocks(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool safe_to_lower) @@ -1260,7 +1300,8 @@ static void dcn401_update_clocks(struct clk_mgr *clk_mgr_base, num_steps = dcn401_build_update_display_clocks_sequence(clk_mgr_base, context, &context->bw_ctx.bw.dcn.clk, - safe_to_lower); + safe_to_lower, + 0); /* execute sequence */ dcn401_execute_block_sequence(clk_mgr_base, num_steps); @@ -1549,6 +1590,14 @@ unsigned int dcn401_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_typ return 0; } +static void dcn401_execute_clk_mgr_block_sequence_bls(struct clk_mgr *clk_mgr_base) +{ + struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); + struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); + + dcn401_execute_block_sequence(clk_mgr_base, clk_mgr401->num_block_sequence_steps); +} + static struct clk_mgr_funcs dcn401_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .get_dtb_ref_clk_frequency = dcn401_get_dtb_ref_freq_khz, @@ -1566,6 +1615,8 @@ static struct clk_mgr_funcs dcn401_funcs = { .get_hard_min_fclk = dcn401_get_hard_min_fclk, .is_dc_mode_present = dcn401_is_dc_mode_present, .get_max_clock_khz = dcn401_get_max_clock_khz, + .build_clock_update_for_bls = dcn401_build_clock_update_for_bls, + .execute_clk_mgr_block_sequence = dcn401_execute_clk_mgr_block_sequence_bls, }; struct clk_mgr_internal *dcn401_clk_mgr_construct( diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.h index 370d2ddd6064..d4cd69a5a8dd 100644 --- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.h @@ -102,6 +102,7 @@ struct dcn401_clk_mgr { struct clk_mgr_internal base; struct dcn401_clk_mgr_block_sequence block_sequence[DCN401_CLK_MGR_MAX_SEQUENCE_SIZE]; + unsigned int num_block_sequence_steps; }; void dcn401_init_clocks(struct clk_mgr *clk_mgr_base); @@ -114,4 +115,12 @@ void dcn401_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr); unsigned int dcn401_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type clk_type); +struct block_sequence_state; + +void dcn401_build_clock_update_for_bls( + struct clk_mgr *clk_mgr_base, + struct dc_state *context, + bool safe_to_lower, + struct block_sequence_state *seq_state); + #endif /* __DCN401_CLK_MGR_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index bcdbf3471039..28339e4b6d67 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1509,7 +1509,7 @@ static void disable_vbios_mode_if_required( struct dc *dc_create(const struct dc_init_data *init_params) { - struct dc *dc = kzalloc_obj(*dc); + struct dc *dc = kvzalloc_obj(*dc); unsigned int full_pipe_count; if (!dc) @@ -1557,7 +1557,7 @@ struct dc *dc_create(const struct dc_init_data *init_params) destruct_dc: dc_destruct(dc); - kfree(dc); + kvfree(dc); return NULL; } @@ -1606,7 +1606,7 @@ void dc_deinit_callbacks(struct dc *dc) void dc_destroy(struct dc **dc) { dc_destruct(*dc); - kfree(*dc); + kvfree(*dc); *dc = NULL; } @@ -2310,7 +2310,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c for (i = 0; i < context->stream_count; i++) { uint32_t prev_dsc_changed = context->streams[i]->update_flags.bits.dsc_changed; - context->streams[i]->update_flags.raw = 0xFFFFFFFF; + stream_update_flags_set_full(&context->streams[i]->update_flags); context->streams[i]->update_flags.bits.dsc_changed = prev_dsc_changed; } @@ -2416,7 +2416,7 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c /* Clear update flags that were set earlier to avoid redundant programming */ for (i = 0; i < context->stream_count; i++) { - context->streams[i]->update_flags.raw = 0x0; + stream_update_flags_clear(&context->streams[i]->update_flags); } old_state = dc->current_state; @@ -2764,7 +2764,7 @@ static bool is_surface_in_context( static struct surface_update_descriptor get_plane_info_update_type(const struct dc_surface_update *u) { - union surface_update_flags *update_flags = &u->surface->update_flags; + struct pipe_update_bits *update_bits = &u->surface->update_bits; struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE }; if (!u->plane_info) @@ -2774,37 +2774,37 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct elevate_update_type(&update_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); if (u->plane_info->color_space != u->surface->color_space) { - update_flags->bits.color_space_change = 1; + update_bits->color_space_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } if (u->plane_info->horizontal_mirror != u->surface->horizontal_mirror) { - update_flags->bits.horizontal_mirror_change = 1; + update_bits->horizontal_mirror_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } if (u->plane_info->rotation != u->surface->rotation) { - update_flags->bits.rotation_change = 1; + update_bits->rotation_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } if (u->plane_info->format != u->surface->format) { - update_flags->bits.pixel_format_change = 1; + update_bits->pixel_format_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } if (u->plane_info->stereo_format != u->surface->stereo_format) { - update_flags->bits.stereo_format_change = 1; + update_bits->stereo_format_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } if (u->plane_info->per_pixel_alpha != u->surface->per_pixel_alpha) { - update_flags->bits.per_pixel_alpha_change = 1; + update_bits->per_pixel_alpha_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } if (u->plane_info->global_alpha_value != u->surface->global_alpha_value) { - update_flags->bits.global_alpha_change = 1; + update_bits->global_alpha_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } @@ -2816,7 +2816,7 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct * stutter period calculation. Triggering a full update will * recalculate stutter period. */ - update_flags->bits.dcc_change = 1; + update_bits->dcc_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } @@ -2825,25 +2825,25 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct /* different bytes per element will require full bandwidth * and DML calculation */ - update_flags->bits.bpp_change = 1; + update_bits->bpp_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } if (u->plane_info->plane_size.surface_pitch != u->surface->plane_size.surface_pitch || u->plane_info->plane_size.chroma_pitch != u->surface->plane_size.chroma_pitch) { - update_flags->bits.plane_size_change = 1; + update_bits->plane_size_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } const struct dc_tiling_info *tiling = &u->plane_info->tiling_info; if (memcmp(tiling, &u->surface->tiling_info, sizeof(*tiling)) != 0) { - update_flags->bits.swizzle_change = 1; + update_bits->swizzle_change = 1; if (tiling->flags.avoid_full_update_on_tiling_change) { elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } else { - update_flags->bits.bandwidth_change = 1; + update_bits->bandwidth_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } } @@ -2853,10 +2853,10 @@ static struct surface_update_descriptor get_plane_info_update_type(const struct } static struct surface_update_descriptor get_scaling_info_update_type( - const struct dc_check_config *check_config, - const struct dc_surface_update *u) + const struct dc_check_config *check_config, + const struct dc_surface_update *u) { - union surface_update_flags *update_flags = &u->surface->update_flags; + struct pipe_update_bits *update_bits = &u->surface->update_bits; struct surface_update_descriptor update_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE }; if (!u->scaling_info) @@ -2873,26 +2873,26 @@ static struct surface_update_descriptor get_scaling_info_update_type( || u->scaling_info->clip_rect.height != u->surface->clip_rect.height || u->scaling_info->scaling_quality.integer_scaling != u->surface->scaling_quality.integer_scaling) { - update_flags->bits.scaling_change = 1; + update_bits->scaling_change = 1; elevate_update_type(&update_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); if (u->scaling_info->src_rect.width > u->surface->src_rect.width || u->scaling_info->src_rect.height > u->surface->src_rect.height) /* Making src rect bigger requires a bandwidth change */ - update_flags->bits.clock_change = 1; + update_bits->clock_change = 1; if ((u->scaling_info->dst_rect.width < u->surface->dst_rect.width || u->scaling_info->dst_rect.height < u->surface->dst_rect.height) && (u->scaling_info->dst_rect.width < u->surface->src_rect.width || u->scaling_info->dst_rect.height < u->surface->src_rect.height)) /* Making dst rect smaller requires a bandwidth change */ - update_flags->bits.bandwidth_change = 1; + update_bits->bandwidth_change = 1; if (u->scaling_info->src_rect.width > (int)check_config->max_optimizable_video_width && (u->scaling_info->clip_rect.width > u->surface->clip_rect.width || u->scaling_info->clip_rect.height > u->surface->clip_rect.height)) /* Changing clip size of a large surface may result in MPC slice count change */ - update_flags->bits.bandwidth_change = 1; + update_bits->bandwidth_change = 1; } if (u->scaling_info->src_rect.x != u->surface->src_rect.x @@ -2902,7 +2902,7 @@ static struct surface_update_descriptor get_scaling_info_update_type( || u->scaling_info->dst_rect.x != u->surface->dst_rect.x || u->scaling_info->dst_rect.y != u->surface->dst_rect.y) { elevate_update_type(&update_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); - update_flags->bits.position_change = 1; + update_bits->position_change = 1; } return update_type; @@ -2913,15 +2913,15 @@ static struct surface_update_descriptor det_surface_update( struct dc_surface_update *u) { struct surface_update_descriptor overall_type = { UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_NONE }; - union surface_update_flags *update_flags = &u->surface->update_flags; + struct pipe_update_bits *update_bits = &u->surface->update_bits; if (u->surface->force_full_update) { - update_flags->raw = 0xFFFFFFFF; + dc_pipe_update_bits_set_full(update_bits); elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); return overall_type; } - update_flags->raw = 0; // Reset all flags + dc_pipe_update_bits_clear(update_bits); struct surface_update_descriptor inner_type = get_plane_info_update_type(u); @@ -2931,87 +2931,112 @@ static struct surface_update_descriptor det_surface_update( elevate_update_type(&overall_type, inner_type.update_type, inner_type.lock_descriptor); if (u->flip_addr) { - update_flags->bits.addr_update = 1; + update_bits->addr_update = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); if (u->flip_addr->address.tmz_surface != u->surface->address.tmz_surface) { - update_flags->bits.tmz_changed = 1; + update_bits->tmz_changed = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } } if (u->in_transfer_func) { - update_flags->bits.in_transfer_func_change = 1; + update_bits->in_transfer_func_change = 1; elevate_update_type(&overall_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } if (u->input_csc_color_matrix) { - update_flags->bits.input_csc_change = 1; + update_bits->input_csc_change = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); } if (u->cursor_csc_color_matrix) { - update_flags->bits.cursor_csc_color_matrix_change = 1; + update_bits->cursor_csc_color_matrix_change = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); } if (u->coeff_reduction_factor) { - update_flags->bits.coeff_reduction_change = 1; + update_bits->coeff_reduction_change = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); } if (u->gamut_remap_matrix) { - update_flags->bits.gamut_remap_change = 1; + update_bits->gamut_remap_change = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); } - if (u->blend_tf || (u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) { - update_flags->bits.gamma_change = 1; + if ((u->cm && u->cm->flags.bits.blend_enable) || + (u->gamma && dce_use_lut(u->plane_info ? u->plane_info->format : u->surface->format))) { + update_bits->gamma_change = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); } - if (u->lut3d_func || u->func_shaper) { - update_flags->bits.lut_3d = 1; + if (u->cm && (u->cm->flags.bits.lut3d_enable || u->cm->flags.bits.shaper_enable)) { + update_bits->lut_3d = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); } + if (u->cm && u->cm->flags.bits.lut3d_dma_enable != u->surface->cm.flags.bits.lut3d_dma_enable && + u->cm->flags.bits.lut3d_enable && u->surface->cm.flags.bits.lut3d_enable) { + /* Toggling 3DLUT loading between DMA and Host is illegal */ + BREAK_TO_DEBUGGER(); + } + + if (u->cm && u->cm->flags.bits.lut3d_enable && !u->cm->flags.bits.lut3d_dma_enable) { + /* Host loading 3DLUT requires full update but only stream lock */ + elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_STREAM); + } + if (u->hdr_mult.value) if (u->hdr_mult.value != u->surface->hdr_mult.value) { // TODO: Should be fast? - update_flags->bits.hdr_mult = 1; + update_bits->hdr_mult = 1; elevate_update_type(&overall_type, UPDATE_TYPE_MED, LOCK_DESCRIPTOR_STREAM); } if (u->sdr_white_level_nits) if (u->sdr_white_level_nits != u->surface->sdr_white_level_nits) { // TODO: Should be fast? - update_flags->bits.sdr_white_level_nits = 1; + update_bits->sdr_white_level_nits = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } if (u->cm_hist_control) { - update_flags->bits.cm_hist_change = 1; + update_bits->cm_hist_change = 1; elevate_update_type(&overall_type, UPDATE_TYPE_FAST, LOCK_DESCRIPTOR_STREAM); } - if (u->cm2_params) { - if (u->cm2_params->component_settings.shaper_3dlut_setting != u->surface->mcm_shaper_3dlut_setting - || u->cm2_params->component_settings.lut1d_enable != u->surface->mcm_lut1d_enable - || u->cm2_params->cm2_luts.lut3d_data.lut3d_src != u->surface->mcm_luts.lut3d_data.lut3d_src) { - update_flags->bits.mcm_transfer_function_enable_change = 1; + + if (u->cm) { + const union dc_plane_cm_flags blend_only_flags = { + .bits = { + .blend_enable = 1, + } + }; + + if (u->cm->flags.bits.shaper_enable != u->surface->cm.flags.bits.shaper_enable + || u->cm->flags.bits.blend_enable != u->surface->cm.flags.bits.blend_enable + || u->cm->flags.bits.lut3d_enable != u->surface->cm.flags.bits.lut3d_enable + || u->cm->flags.bits.lut3d_dma_enable != u->surface->cm.flags.bits.lut3d_dma_enable) { + update_bits->mcm_transfer_function_enable_change = 1; + elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); + } + + if ((u->cm->flags.all != blend_only_flags.all && u->cm->flags.all != 0) || + (u->surface->cm.flags.all != blend_only_flags.all && u->surface->cm.flags.all != 0)) { elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } } - if (update_flags->bits.lut_3d && - u->surface->mcm_luts.lut3d_data.lut3d_src != DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) { + if (update_bits->lut_3d && + !u->surface->cm.flags.bits.lut3d_dma_enable) { elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } if (check_config->enable_legacy_fast_update && - (update_flags->bits.gamma_change || - update_flags->bits.gamut_remap_change || - update_flags->bits.input_csc_change || - update_flags->bits.cm_hist_change || - update_flags->bits.coeff_reduction_change)) { + (update_bits->gamma_change || + update_bits->gamut_remap_change || + update_bits->input_csc_change || + update_bits->cm_hist_change || + update_bits->coeff_reduction_change)) { elevate_update_type(&overall_type, UPDATE_TYPE_FULL, LOCK_DESCRIPTOR_GLOBAL); } return overall_type; @@ -3036,7 +3061,7 @@ static void force_immediate_gsl_plane_flip(struct dc *dc, struct dc_surface_upda if (has_flip_immediate_plane && surface_count > 1) { for (i = 0; i < surface_count; i++) { if (updates[i].surface->flip_immediate) - updates[i].surface->update_flags.bits.addr_update = 1; + updates[i].surface->update_bits.addr_update = 1; } } } @@ -3191,9 +3216,9 @@ struct surface_update_descriptor dc_check_update_surfaces_for_stream( struct dc_stream_update *stream_update) { if (stream_update) - stream_update->stream->update_flags.raw = 0; + stream_update_flags_clear(&stream_update->stream->update_flags); for (int i = 0; i < surface_count; i++) - updates[i].surface->update_flags.raw = 0; + dc_pipe_update_bits_clear(&updates[i].surface->update_bits); return check_update_surfaces_for_stream(check_config, updates, surface_count, stream_update); } @@ -3304,24 +3329,55 @@ static void copy_surface_update_to_plane( sizeof(struct dc_transfer_func_distributed_points)); } - if (srf_update->cm2_params) { - surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting; - surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable; - surface->mcm_luts = srf_update->cm2_params->cm2_luts; + /* Shaper, 3DLUT, 1DLUT */ + if (srf_update->cm) { + struct kref refcount = surface->cm.refcount; + + memcpy(&surface->cm, srf_update->cm, sizeof(surface->cm)); + surface->cm.refcount = refcount; + +#ifndef TRIM_CM2 + /* Populate mcm_luts from cm for legacy consumers (dml2, hwseq) */ + surface->mcm_luts.lut1d_func = &surface->cm.blend_func; + surface->mcm_luts.shaper = &surface->cm.shaper_func; + if (srf_update->cm->flags.bits.lut3d_dma_enable) { + surface->mcm_luts.lut3d_data.lut3d_src = DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM; + surface->mcm_luts.lut3d_data.gpu_mem_params.addr = surface->cm.lut3d_dma.addr; + surface->mcm_luts.lut3d_data.gpu_mem_params.layout = + (surface->cm.lut3d_dma.swizzle == CM_LUT_3D_SWIZZLE_LINEAR_RGB) ? + DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB : + (surface->cm.lut3d_dma.swizzle == CM_LUT_3D_SWIZZLE_LINEAR_BGR) ? + DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR : + DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR; + surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.format = + (surface->cm.lut3d_dma.format == CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB) ? + DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB : + (surface->cm.lut3d_dma.format == CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB) ? + DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB : + DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10; + surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias = + surface->cm.lut3d_dma.bias; + surface->mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale = + surface->cm.lut3d_dma.scale; + surface->mcm_luts.lut3d_data.gpu_mem_params.component_order = + DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA; + surface->mcm_luts.lut3d_data.gpu_mem_params.size = DC_CM2_GPU_MEM_SIZE_TRANSFORMED; + surface->mcm_luts.lut3d_data.mpc_3dlut_enable = (srf_update->cm->flags.bits.lut3d_enable != 0); + } else { + surface->mcm_luts.lut3d_data.lut3d_src = DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM; + surface->mcm_luts.lut3d_data.lut3d_func = &surface->cm.lut3d_func; + } + + if (srf_update->cm->flags.bits.shaper_enable && + srf_update->cm->flags.bits.lut3d_enable) + surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT; + else if (srf_update->cm->flags.bits.shaper_enable) + surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER; + else + surface->mcm_shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL; +#endif /* TRIM_CM2 */ } - if (srf_update->func_shaper) { - memcpy(&surface->in_shaper_func, srf_update->func_shaper, - sizeof(surface->in_shaper_func)); - - if (surface->mcm_shaper_3dlut_setting >= DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER) - surface->mcm_luts.shaper = &surface->in_shaper_func; - } - - if (srf_update->lut3d_func) - memcpy(&surface->lut3d_func, srf_update->lut3d_func, - sizeof(surface->lut3d_func)); - if (srf_update->hdr_mult.value) surface->hdr_mult = srf_update->hdr_mult; @@ -3330,15 +3386,10 @@ static void copy_surface_update_to_plane( surface->sdr_white_level_nits = srf_update->sdr_white_level_nits; - if (srf_update->blend_tf) { - memcpy(&surface->blend_tf, srf_update->blend_tf, - sizeof(surface->blend_tf)); - - if (surface->mcm_lut1d_enable) - surface->mcm_luts.lut1d_func = &surface->blend_tf; - } - - if (srf_update->cm2_params || srf_update->blend_tf) + if (srf_update->cm && + (srf_update->cm->flags.bits.blend_enable || + srf_update->cm->flags.bits.shaper_enable || + srf_update->cm->flags.bits.lut3d_enable)) surface->lut_bank_a = !surface->lut_bank_a; if (srf_update->input_csc_color_matrix) @@ -3714,11 +3765,11 @@ static bool update_planes_and_stream_state(struct dc *dc, if (update_type == UPDATE_TYPE_FULL) { if (stream_update) { uint32_t dsc_changed = stream_update->stream->update_flags.bits.dsc_changed; - stream_update->stream->update_flags.raw = 0xFFFFFFFF; + stream_update_flags_set_full(&stream_update->stream->update_flags); stream_update->stream->update_flags.bits.dsc_changed = dsc_changed; } for (i = 0; i < surface_count; i++) - srf_updates[i].surface->update_flags.raw = 0xFFFFFFFF; + dc_pipe_update_bits_set_full(&srf_updates[i].surface->update_bits); } if (update_type >= update_surface_trace_level) @@ -3767,7 +3818,7 @@ static bool update_planes_and_stream_state(struct dc *dc, if (update_type != UPDATE_TYPE_MED) continue; - if (surface->update_flags.bits.position_change) { + if (surface->update_bits.position_change) { for (j = 0; j < dc->res_pool->pipe_count; j++) { struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; @@ -4077,8 +4128,6 @@ static void commit_planes_do_stream_update_sequence(struct dc *dc, { int j; struct block_sequence_state seq_state = { .steps = block_sequence, .num_steps = num_steps }; - struct dsc_config dsc_cfgs[MAX_PIPES]; - struct dsc_optc_config dsc_optc_cfgs[MAX_PIPES]; unsigned int dsc_cfg_index = 0; *num_steps = 0; // Initialize to 0 @@ -4150,11 +4199,13 @@ static void commit_planes_do_stream_update_sequence(struct dc *dc, if (stream_update->dsc_config) if (dsc_cfg_index < MAX_PIPES) { + struct dsc_config dsc_cfg; + struct dsc_optc_config dsc_optc_cfg; + add_link_update_dsc_config_sequence(&seq_state, pipe_ctx, - &dsc_cfgs[dsc_cfg_index], - &dsc_optc_cfgs[dsc_cfg_index]); - dsc_cfg_index++; + &dsc_cfg, + &dsc_optc_cfg); } if (stream_update->mst_bw_update) { @@ -4205,8 +4256,8 @@ static void commit_planes_do_stream_update_sequence(struct dc *dc, hwss_add_dc_set_optimized_required(&seq_state, dc, true); } else { - if (get_seamless_boot_stream_count(context) == 0) - hwss_add_prepare_bandwidth(&seq_state, dc, dc->current_state); + if (get_seamless_boot_stream_count(context) == 0 && dc->hwss.prepare_bandwidth_sequence) + dc->hwss.prepare_bandwidth_sequence(dc, dc->current_state, &seq_state); hwss_add_link_set_dpms_on(&seq_state, dc->current_state, dpms_pipe_ctx); } } else if (pipe_ctx->stream->link->wa_flags.blank_stream_on_ocs_change && stream_update->output_color_space @@ -4550,14 +4601,23 @@ static void build_dmub_update_dirty_rect( } } -static bool check_address_only_update(union surface_update_flags update_flags) +/** + * dc_check_address_only_update - Check if addr_update is the sole flag set + * + * @update_bits: The pipe update bits to check + * + * Determines whether an update contains only an address change with no other + * pending updates. + * + * Return: %true if addr_update is the sole bit set, %false otherwise. + */ +bool dc_check_address_only_update(struct pipe_update_bits update_bits) { - union surface_update_flags addr_only_update_flags; - addr_only_update_flags.raw = 0; - addr_only_update_flags.bits.addr_update = 1; + struct pipe_update_bits check = update_bits; /* 1. Copy all flags from input */ - return update_flags.bits.addr_update && - !(update_flags.raw & ~addr_only_update_flags.raw); + check.addr_update = 0; /* 2. Zero the addr_update bit in the copy */ + return update_bits.addr_update && /* 3. Check addr_update was set in original */ + !dc_pipe_update_bits_is_any_set(&check); /* 4. Check no other bits remain in the copy */ } /** @@ -4617,7 +4677,7 @@ static void commit_plane_for_stream_offload_fams2_flip(struct dc *dc, continue; /* update pipe context for plane */ - if (pipe_ctx->plane_state->update_flags.bits.addr_update) + if (pipe_ctx->plane_state->update_bits.addr_update) dc->hwss.update_plane_addr(dc, pipe_ctx); } } @@ -4655,8 +4715,8 @@ static void commit_planes_for_stream_fast(struct dc *dc, should_offload_fams2_flip = true; for (i = 0; i < surface_count; i++) { if (srf_updates[i].surface && - srf_updates[i].surface->update_flags.raw && - !check_address_only_update(srf_updates[i].surface->update_flags)) { + dc_pipe_update_bits_is_any_set(&srf_updates[i].surface->update_bits) && + !dc_check_address_only_update(srf_updates[i].surface->update_bits)) { /* more than address update, need to acquire FAMS2 lock */ should_offload_fams2_flip = false; break; @@ -4747,7 +4807,7 @@ static void commit_planes_for_stream_fast(struct dc *dc, * so no need to clear here. */ if (top_pipe_to_program->stream) - top_pipe_to_program->stream->update_flags.raw = 0; + stream_update_flags_clear(&top_pipe_to_program->stream->update_flags); } static void commit_planes_for_stream(struct dc *dc, @@ -5073,11 +5133,9 @@ static void commit_planes_for_stream(struct dc *dc, if (!should_update_pipe_for_plane(context, pipe_ctx, plane_state)) continue; - if (srf_updates[i].cm2_params && - srf_updates[i].cm2_params->cm2_luts.lut3d_data.lut3d_src == - DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM && - srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting == - DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT && + if (srf_updates[i].cm && + srf_updates[i].cm->flags.bits.lut3d_enable && + srf_updates[i].cm->flags.bits.lut3d_dma_enable && dc->hwss.trigger_3dlut_dma_load) dc->hwss.trigger_3dlut_dma_load(dc, pipe_ctx); @@ -5087,7 +5145,7 @@ static void commit_planes_for_stream(struct dc *dc, dc->hwss.program_triplebuffer( dc, pipe_ctx, pipe_ctx->plane_state->triplebuffer_flips); } - if (pipe_ctx->plane_state->update_flags.bits.addr_update) + if (pipe_ctx->plane_state->update_bits.addr_update) dc->hwss.update_plane_addr(dc, pipe_ctx); } } @@ -5178,7 +5236,7 @@ static void commit_planes_for_stream(struct dc *dc, if (pipe_ctx->bottom_pipe || pipe_ctx->next_odm_pipe || !pipe_ctx->stream || !should_update_pipe_for_stream(context, pipe_ctx, stream) || - !pipe_ctx->plane_state->update_flags.bits.addr_update || + !pipe_ctx->plane_state->update_bits.addr_update || pipe_ctx->plane_state->skip_manual_trigger) continue; @@ -5617,7 +5675,7 @@ static bool commit_minimal_transition_state(struct dc *dc, /* force full surface update */ for (i = 0; i < dc->current_state->stream_count; i++) { for (j = 0; j < (unsigned int)dc->current_state->stream_status[i].plane_count; j++) { - dc->current_state->stream_status[i].plane_states[j]->update_flags.raw = 0xFFFFFFFF; + dc_pipe_update_bits_set_full(&dc->current_state->stream_status[i].plane_states[j]->update_bits); } } @@ -5792,14 +5850,9 @@ static bool full_update_required( (srf_updates[i].sdr_white_level_nits && srf_updates[i].sdr_white_level_nits != srf_updates->surface->sdr_white_level_nits) || srf_updates[i].in_transfer_func || - srf_updates[i].func_shaper || - srf_updates[i].lut3d_func || srf_updates[i].surface->force_full_update || (srf_updates[i].flip_addr && - srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface) || - (srf_updates[i].cm2_params && - (srf_updates[i].cm2_params->component_settings.shaper_3dlut_setting != srf_updates[i].surface->mcm_shaper_3dlut_setting || - srf_updates[i].cm2_params->component_settings.lut1d_enable != srf_updates[i].surface->mcm_lut1d_enable)))) + srf_updates[i].flip_addr->address.tmz_surface != srf_updates[i].surface->address.tmz_surface))) return true; } @@ -6063,17 +6116,17 @@ static bool update_planes_and_stream_v3(struct dc *dc, return true; } -static void clear_update_flags(struct dc_surface_update *srf_updates, +static void clear_update_bits(struct dc_surface_update *srf_updates, int surface_count, struct dc_stream_state *stream) { int i; if (stream) - stream->update_flags.raw = 0; + stream_update_flags_clear(&stream->update_flags); for (i = 0; i < surface_count; i++) if (srf_updates[i].surface) - srf_updates[i].surface->update_flags.raw = 0; + dc_pipe_update_bits_clear(&srf_updates[i].surface->update_bits); } bool dc_update_planes_and_stream(struct dc *dc, @@ -6125,7 +6178,7 @@ void dc_commit_updates_for_stream(struct dc *dc, } if (ret && dc->ctx->dce_version >= DCN_VERSION_3_2) - clear_update_flags(srf_updates, surface_count, stream); + clear_update_bits(srf_updates, surface_count, stream); } uint8_t dc_get_current_stream_count(struct dc *dc) @@ -7542,7 +7595,7 @@ bool dc_capture_register_software_state(struct dc *dc, struct dc_register_softwa struct dc_plane_state *plane_state = pipe_ctx->plane_state; /* MPCC blending tree and mode control - capture actual blend configuration */ - state->mpc.mpcc_mode[i] = (plane_state->blend_tf.type != TF_TYPE_BYPASS) ? 1 : 0; + state->mpc.mpcc_mode[i] = (plane_state->cm.blend_func.type != TF_TYPE_BYPASS) ? 1 : 0; state->mpc.mpcc_alpha_blend_mode[i] = plane_state->per_pixel_alpha ? 1 : 0; state->mpc.mpcc_alpha_multiplied_mode[i] = plane_state->pre_multiplied_alpha ? 1 : 0; state->mpc.mpcc_blnd_active_overlap_only[i] = 0; /* Default - no overlap restriction */ @@ -7875,7 +7928,7 @@ struct dc_update_scratch_space { struct dc_stream_state *stream; struct dc_stream_update *stream_update; bool update_v3; - bool do_clear_update_flags; + bool do_clear_update_bits; enum surface_update_type update_type; struct dc_state *new_context; enum update_v3_flow flow; @@ -7918,8 +7971,8 @@ static bool update_planes_and_stream_cleanup_v2( const struct dc_update_scratch_space *scratch ) { - if (scratch->do_clear_update_flags) - clear_update_flags(scratch->surface_updates, scratch->surface_count, scratch->stream); + if (scratch->do_clear_update_bits) + clear_update_bits(scratch->surface_updates, scratch->surface_count, scratch->stream); return false; } @@ -8173,8 +8226,8 @@ static bool update_planes_and_stream_cleanup_v3( ASSERT(false); } - if (scratch->do_clear_update_flags) - clear_update_flags(scratch->surface_updates, scratch->surface_count, scratch->stream); + if (scratch->do_clear_update_bits) + clear_update_bits(scratch->surface_updates, scratch->surface_count, scratch->stream); return false; } @@ -8197,7 +8250,7 @@ struct dc_update_scratch_space *dc_update_planes_and_stream_init( .stream = stream, .stream_update = stream_update, .update_v3 = version >= DCN_VERSION_4_01 || version == DCN_VERSION_3_2 || version == DCN_VERSION_3_21, - .do_clear_update_flags = version >= DCN_VERSION_1_0, + .do_clear_update_bits = version >= DCN_VERSION_1_0, }; return scratch; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c index 88446817a71f..e47c8cf5d036 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c @@ -37,6 +37,7 @@ #include "dchubbub.h" #include "dccg.h" #include "abm.h" +#include "clk_mgr.h" #include "dcn10/dcn10_hubbub.h" #include "dce/dmub_hw_lock_mgr.h" #include "link_service.h" @@ -1028,20 +1029,20 @@ void hwss_build_fast_sequence(struct dc *dc, current_mpc_pipe = current_pipe; while (current_mpc_pipe) { if (current_mpc_pipe->plane_state) { - if (dc->hwss.set_flip_control_gsl && current_mpc_pipe->plane_state->update_flags.raw) { + if (dc->hwss.set_flip_control_gsl && dc_pipe_update_bits_is_any_set(¤t_mpc_pipe->plane_state->update_bits)) { block_sequence[*num_steps].params.set_flip_control_gsl_params.hubp = current_mpc_pipe->plane_res.hubp; block_sequence[*num_steps].params.set_flip_control_gsl_params.flip_immediate = current_mpc_pipe->plane_state->flip_immediate; block_sequence[*num_steps].func = HUBP_SET_FLIP_CONTROL_GSL; (*num_steps)++; } - if (dc->hwss.program_triplebuffer && dc->debug.enable_tri_buf && current_mpc_pipe->plane_state->update_flags.raw) { + if (dc->hwss.program_triplebuffer && dc->debug.enable_tri_buf && dc_pipe_update_bits_is_any_set(¤t_mpc_pipe->plane_state->update_bits)) { block_sequence[*num_steps].params.program_triplebuffer_params.dc = dc; block_sequence[*num_steps].params.program_triplebuffer_params.pipe_ctx = current_mpc_pipe; block_sequence[*num_steps].params.program_triplebuffer_params.enableTripleBuffer = current_mpc_pipe->plane_state->triplebuffer_flips; block_sequence[*num_steps].func = HUBP_PROGRAM_TRIPLEBUFFER; (*num_steps)++; } - if (dc->hwss.update_plane_addr && current_mpc_pipe->plane_state->update_flags.bits.addr_update) { + if (dc->hwss.update_plane_addr && current_mpc_pipe->plane_state->update_bits.addr_update) { if (resource_is_pipe_type(current_mpc_pipe, OTG_MASTER) && stream_status->mall_stream_config.type == SUBVP_MAIN) { block_sequence[*num_steps].params.subvp_save_surf_addr.dc_dmub_srv = dc->ctx->dmub_srv; @@ -1057,7 +1058,7 @@ void hwss_build_fast_sequence(struct dc *dc, (*num_steps)++; } - if (hws->funcs.set_input_transfer_func && current_mpc_pipe->plane_state->update_flags.bits.gamma_change) { + if (hws->funcs.set_input_transfer_func && current_mpc_pipe->plane_state->update_bits.gamma_change) { block_sequence[*num_steps].params.set_input_transfer_func_params.dc = dc; block_sequence[*num_steps].params.set_input_transfer_func_params.pipe_ctx = current_mpc_pipe; block_sequence[*num_steps].params.set_input_transfer_func_params.plane_state = current_mpc_pipe->plane_state; @@ -1066,23 +1067,23 @@ void hwss_build_fast_sequence(struct dc *dc, } if (dc->hwss.program_gamut_remap && - (current_mpc_pipe->plane_state->update_flags.bits.gamut_remap_change || + (current_mpc_pipe->plane_state->update_bits.gamut_remap_change || current_mpc_pipe->stream->update_flags.bits.gamut_remap)) { block_sequence[*num_steps].params.program_gamut_remap_params.pipe_ctx = current_mpc_pipe; block_sequence[*num_steps].func = DPP_PROGRAM_GAMUT_REMAP; (*num_steps)++; } - if (current_mpc_pipe->plane_state->update_flags.bits.input_csc_change) { + if (current_mpc_pipe->plane_state->update_bits.input_csc_change) { block_sequence[*num_steps].params.setup_dpp_params.pipe_ctx = current_mpc_pipe; block_sequence[*num_steps].func = DPP_SETUP_DPP; (*num_steps)++; } - if (current_mpc_pipe->plane_state->update_flags.bits.coeff_reduction_change) { + if (current_mpc_pipe->plane_state->update_bits.coeff_reduction_change) { block_sequence[*num_steps].params.program_bias_and_scale_params.pipe_ctx = current_mpc_pipe; block_sequence[*num_steps].func = DPP_PROGRAM_BIAS_AND_SCALE; (*num_steps)++; } - if (current_mpc_pipe->plane_state->update_flags.bits.cm_hist_change) { + if (current_mpc_pipe->plane_state->update_bits.cm_hist_change) { block_sequence[*num_steps].params.control_cm_hist_params.dpp = current_mpc_pipe->plane_res.dpp; block_sequence[*num_steps].params.control_cm_hist_params.cm_hist_control @@ -1095,7 +1096,7 @@ void hwss_build_fast_sequence(struct dc *dc, if (current_mpc_pipe->plane_res.dpp && current_mpc_pipe->plane_res.dpp->funcs->set_cursor_matrix && - current_mpc_pipe->plane_state->update_flags.bits.cursor_csc_color_matrix_change) { + current_mpc_pipe->plane_state->update_bits.cursor_csc_color_matrix_change) { block_sequence[*num_steps].params.dpp_set_cursor_matrix_params.dpp = current_mpc_pipe->plane_res.dpp; block_sequence[*num_steps].params.dpp_set_cursor_matrix_params.color_space = current_mpc_pipe->plane_state->color_space; block_sequence[*num_steps].params.dpp_set_cursor_matrix_params.cursor_csc_color_matrix = ¤t_mpc_pipe->plane_state->cursor_csc_color_matrix; @@ -1176,7 +1177,7 @@ void hwss_build_fast_sequence(struct dc *dc, while (current_mpc_pipe) { if (!current_mpc_pipe->bottom_pipe && !current_mpc_pipe->next_odm_pipe && current_mpc_pipe->stream && current_mpc_pipe->plane_state && - current_mpc_pipe->plane_state->update_flags.bits.addr_update && + current_mpc_pipe->plane_state->update_bits.addr_update && !current_mpc_pipe->plane_state->skip_manual_trigger) { if (dc->hwss.program_cursor_offload_now) { block_sequence[*num_steps].params.program_cursor_update_now_params.dc = dc; @@ -1668,6 +1669,21 @@ void hwss_execute_sequence(struct dc *dc, case LINK_SET_DPMS_ON: hwss_link_set_dpms_on(params); break; + case CLK_MGR_SET_MAX_MEMCLK: + hwss_clk_mgr_set_max_memclk(params); + break; + case CLK_MGR_UPDATE_CLOCKS: + hwss_clk_mgr_update_clocks(params); + break; + case HUBBUB_PROGRAM_WATERMARKS: + hwss_hubbub_program_watermarks(params); + break; + case HUBBUB_PROGRAM_ARBITER: + hwss_hubbub_program_arbiter(params); + break; + case HUBBUB_PROGRAM_COMPBUF_SEGMENTS: + hwss_hubbub_program_compbuf_segments(params); + break; default: ASSERT(false); break; @@ -3849,6 +3865,70 @@ void hwss_dsc_set_config_simple(union block_sequence_params *params) dsc->funcs->dsc_set_config(dsc, dsc_cfg, dsc_optc_cfg); } +/* + * Clock manager executor functions + */ +void hwss_clk_mgr_set_max_memclk(union block_sequence_params *params) +{ + struct clk_mgr *clk_mgr = params->clk_mgr_set_max_memclk_params.clk_mgr; + unsigned int memclk_mhz = params->clk_mgr_set_max_memclk_params.memclk_mhz; + + if (clk_mgr && clk_mgr->funcs && clk_mgr->funcs->set_max_memclk) + clk_mgr->funcs->set_max_memclk(clk_mgr, memclk_mhz); +} + +void hwss_clk_mgr_update_clocks(union block_sequence_params *params) +{ + struct clk_mgr *clk_mgr = params->clk_mgr_update_clocks_params.clk_mgr; + + if (clk_mgr && clk_mgr->funcs && clk_mgr->funcs->execute_clk_mgr_block_sequence) + clk_mgr->funcs->execute_clk_mgr_block_sequence(clk_mgr); +} + +/* + * Hubbub executor functions + */ +void hwss_hubbub_program_watermarks(union block_sequence_params *params) +{ + struct dc *dc = params->hubbub_program_watermarks_params.dc; + struct hubbub *hubbub = params->hubbub_program_watermarks_params.hubbub; + union dcn_watermark_set *watermarks = params->hubbub_program_watermarks_params.watermarks; + unsigned int refclk_mhz = params->hubbub_program_watermarks_params.refclk_mhz; + bool safe_to_lower = params->hubbub_program_watermarks_params.safe_to_lower; + + if (hubbub && hubbub->funcs && hubbub->funcs->program_watermarks) { + bool wm_changed = hubbub->funcs->program_watermarks(hubbub, watermarks, refclk_mhz, safe_to_lower); + + if (dc && !safe_to_lower) + dc->optimized_required |= wm_changed; + } +} + +void hwss_hubbub_program_arbiter(union block_sequence_params *params) +{ + struct dc *dc = params->hubbub_program_arbiter_params.dc; + struct hubbub *hubbub = params->hubbub_program_arbiter_params.hubbub; + struct dml2_display_arb_regs *arb_regs = params->hubbub_program_arbiter_params.arb_regs; + bool safe_to_lower = params->hubbub_program_arbiter_params.safe_to_lower; + + if (hubbub && hubbub->funcs && hubbub->funcs->program_arbiter) { + bool arb_changed = hubbub->funcs->program_arbiter(hubbub, arb_regs, safe_to_lower); + + if (dc && !safe_to_lower) + dc->optimized_required |= arb_changed; + } +} + +void hwss_hubbub_program_compbuf_segments(union block_sequence_params *params) +{ + struct hubbub *hubbub = params->hubbub_program_compbuf_segments_params.hubbub; + unsigned int compbuf_size = params->hubbub_program_compbuf_segments_params.compbuf_size; + bool safe_to_lower = params->hubbub_program_compbuf_segments_params.safe_to_lower; + + if (hubbub && hubbub->funcs && hubbub->funcs->program_compbuf_segments) + hubbub->funcs->program_compbuf_segments(hubbub, compbuf_size, safe_to_lower); +} + void hwss_add_dccg_set_dto_dscclk(struct block_sequence_state *seq_state, struct dccg *dccg, int inst, int num_slices_h) { @@ -4909,6 +4989,9 @@ void hwss_add_hpo_dp_stream_enc_update_dp_info_packets_sdp_line_num(struct block } } +/* + * Clock manager helper functions + */ void hwss_add_hpo_dp_stream_enc_update_dp_info_packets(struct block_sequence_state *seq_state, struct pipe_ctx *pipe_ctx) { @@ -4919,6 +5002,28 @@ void hwss_add_hpo_dp_stream_enc_update_dp_info_packets(struct block_sequence_sta } } +void hwss_add_clk_mgr_set_max_memclk(struct block_sequence_state *seq_state, + struct clk_mgr *clk_mgr, + unsigned int memclk_mhz) +{ + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + seq_state->steps[*seq_state->num_steps].func = CLK_MGR_SET_MAX_MEMCLK; + seq_state->steps[*seq_state->num_steps].params.clk_mgr_set_max_memclk_params.clk_mgr = clk_mgr; + seq_state->steps[*seq_state->num_steps].params.clk_mgr_set_max_memclk_params.memclk_mhz = memclk_mhz; + (*seq_state->num_steps)++; + } +} + +void hwss_add_clk_mgr_update_clocks(struct block_sequence_state *seq_state, + struct clk_mgr *clk_mgr) +{ + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + seq_state->steps[*seq_state->num_steps].func = CLK_MGR_UPDATE_CLOCKS; + seq_state->steps[*seq_state->num_steps].params.clk_mgr_update_clocks_params.clk_mgr = clk_mgr; + (*seq_state->num_steps)++; + } +} + void hwss_add_stream_enc_update_dp_info_packets_sdp_line_num(struct block_sequence_state *seq_state, struct pipe_ctx *pipe_ctx) { @@ -5022,6 +5127,26 @@ void hwss_add_setup_periodic_interrupt(struct block_sequence_state *seq_state, (*seq_state->num_steps)++; } } +/* + * Hubbub helper functions + */ +void hwss_add_hubbub_program_watermarks(struct block_sequence_state *seq_state, + struct dc *dc, + struct hubbub *hubbub, + union dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower) +{ + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + seq_state->steps[*seq_state->num_steps].func = HUBBUB_PROGRAM_WATERMARKS; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_watermarks_params.dc = dc; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_watermarks_params.hubbub = hubbub; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_watermarks_params.watermarks = watermarks; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_watermarks_params.refclk_mhz = refclk_mhz; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_watermarks_params.safe_to_lower = safe_to_lower; + (*seq_state->num_steps)++; + } +} void hwss_add_dp_trace_source_sequence(struct block_sequence_state *seq_state, struct dc_link *link, @@ -5035,6 +5160,22 @@ void hwss_add_dp_trace_source_sequence(struct block_sequence_state *seq_state, } } +void hwss_add_hubbub_program_arbiter(struct block_sequence_state *seq_state, + struct dc *dc, + struct hubbub *hubbub, + struct dml2_display_arb_regs *arb_regs, + bool safe_to_lower) +{ + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + seq_state->steps[*seq_state->num_steps].func = HUBBUB_PROGRAM_ARBITER; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_arbiter_params.dc = dc; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_arbiter_params.hubbub = hubbub; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_arbiter_params.arb_regs = arb_regs; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_arbiter_params.safe_to_lower = safe_to_lower; + (*seq_state->num_steps)++; + } +} + void hwss_add_set_dmdata_attributes(struct block_sequence_state *seq_state, struct pipe_ctx *pipe_ctx) { @@ -5119,6 +5260,19 @@ void hwss_add_disable_audio_stream(struct block_sequence_state *seq_state, (*seq_state->num_steps)++; } } +void hwss_add_hubbub_program_compbuf_segments(struct block_sequence_state *seq_state, + struct hubbub *hubbub, + unsigned int compbuf_size, + bool safe_to_lower) +{ + if (*seq_state->num_steps < MAX_HWSS_BLOCK_SEQUENCE_SIZE) { + seq_state->steps[*seq_state->num_steps].func = HUBBUB_PROGRAM_COMPBUF_SEGMENTS; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_compbuf_segments_params.hubbub = hubbub; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_compbuf_segments_params.compbuf_size = compbuf_size; + seq_state->steps[*seq_state->num_steps].params.hubbub_program_compbuf_segments_params.safe_to_lower = safe_to_lower; + (*seq_state->num_steps)++; + } +} void hwss_add_prepare_bandwidth(struct block_sequence_state *seq_state, struct dc *dc, diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 5f6cc1b1f788..b21d41df0fab 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -4412,14 +4412,13 @@ enum dc_status dc_validate_with_context(struct dc *dc, struct dc_stream_state *unchanged_streams[MAX_PIPES] = { 0 }; struct dc_stream_state *del_streams[MAX_PIPES] = { 0 }; struct dc_stream_state *add_streams[MAX_PIPES] = { 0 }; - int old_stream_count = context->stream_count; + unsigned int old_stream_count = context->stream_count; enum dc_status res = DC_ERROR_UNEXPECTED; - int unchanged_streams_count = 0; - int del_streams_count = 0; - int add_streams_count = 0; + unsigned int unchanged_streams_count = 0; + unsigned int del_streams_count = 0; + unsigned int add_streams_count = 0; bool found = false; - int i, j; - unsigned int k; + unsigned int i, j, k; DC_LOGGER_INIT(dc->ctx->logger); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c index 72845fc788f3..88e825a6582c 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c @@ -45,14 +45,13 @@ void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *plane_sta plane_state->in_transfer_func.type = TF_TYPE_BYPASS; - plane_state->in_shaper_func.type = TF_TYPE_BYPASS; - - plane_state->lut3d_func.state.raw = 0; - - plane_state->blend_tf.type = TF_TYPE_BYPASS; - plane_state->pre_multiplied_alpha = true; + /* CM */ + plane_state->cm.shaper_func.type = TF_TYPE_BYPASS; + plane_state->cm.blend_func.type = TF_TYPE_BYPASS; + plane_state->cm.lut3d_func.state.raw = 0; + plane_state->cm.flags.all = 0; } void dc_plane_destruct(struct dc_plane_state *plane_state) @@ -282,6 +281,39 @@ void dc_3dlut_func_retain(struct dc_3dlut *lut) kref_get(&lut->refcount); } +static void dc_plane_cm_free(struct kref *kref) +{ + struct dc_plane_cm *cm = container_of(kref, struct dc_plane_cm, refcount); + + kvfree(cm); +} + +struct dc_plane_cm *dc_plane_cm_create(void) +{ + struct dc_plane_cm *cm = kvzalloc(sizeof(*cm), GFP_KERNEL); + + if (cm == NULL) + goto alloc_fail; + + kref_init(&cm->refcount); + + return cm; + +alloc_fail: + return NULL; + +} + +void dc_plane_cm_release(struct dc_plane_cm *cm) +{ + kref_put(&cm->refcount, dc_plane_cm_free); +} + +void dc_plane_cm_retain(struct dc_plane_cm *cm) +{ + kref_get(&cm->refcount); +} + void dc_plane_force_dcc_and_tiling_disable(struct dc_plane_state *plane_state, bool clear_tiling) { diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 82d02ebbd829..13c1f7cd9d7d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -65,7 +65,7 @@ struct dcn_dsc_reg_state; struct dcn_optc_reg_state; struct dcn_dccg_reg_state; -#define DC_VER "3.2.384" +#define DC_VER "3.2.388" /** * MAX_SURFACES - representative of the upper bound of surfaces that can be piped to a single CRTC @@ -591,7 +591,6 @@ struct dc_config { bool enable_mipi_converter_optimization; bool enable_frl; bool force_hdmi21_frl_enc_enable; - bool skip_frl_pretraining; bool use_default_clock_table; bool force_bios_enable_lttpr; uint8_t force_bios_fixed_vs; @@ -1129,8 +1128,6 @@ struct dc_debug_options { unsigned int force_fclk_khz; bool enable_tri_buf; bool ips_disallow_entry; - bool dmub_offload_enabled; - bool dmcub_emulation; bool disable_idle_power_optimizations; unsigned int mall_size_override; unsigned int mall_additional_timer_percent; @@ -1152,7 +1149,6 @@ struct dc_debug_options { bool validate_dml_output; bool enable_dmcub_surface_flip; bool usbc_combo_phy_reset_wa; - bool force_vrr; bool force_fva; int max_frl_rate; unsigned int force_frl_rate; @@ -1290,6 +1286,8 @@ struct dc_debug_options { unsigned int min_deep_sleep_dcfclk_khz; unsigned int force_odm2to1_for_edp_pixclk_mhz; bool enable_replay_esd_recovery; + uint8_t iommu_mismatch_temp_wka; + bool disable_dynamic_expansion_for_test_pattern; }; @@ -1332,7 +1330,6 @@ struct dc_init_data { enum dce_environment dce_environment; struct dmub_offload_funcs *dmub_if; - struct dc_reg_helper_state *dmub_offload; struct dc_config flags; uint64_t log_mask; @@ -1488,6 +1485,47 @@ struct dc_3dlut { struct fixed31_32 hdr_multiplier; union dc_3dlut_state state; }; + +/* 3DLUT DMA (Fast Load) params */ +struct dc_3dlut_dma { + struct dc_plane_address addr; + enum dc_cm_lut_swizzle swizzle; + enum dc_cm_lut_pixel_format format; + uint16_t bias; /* FP1.5.10 */ + uint16_t scale; /* FP1.5.10 */ + enum dc_cm_lut_size size; +}; + +/* color manager */ +union dc_plane_cm_flags { + unsigned int all; + struct { + unsigned int shaper_enable : 1; + unsigned int lut3d_enable : 1; + unsigned int blend_enable : 1; + /* whether legacy (lut3d_func) or DMA is valid */ + unsigned int lut3d_dma_enable : 1; +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) + /* RMCM lut to be used instead of MCM */ + unsigned int rmcm_enable : 1; + unsigned int reserved: 27; +#else + unsigned int reserved: 28; +#endif + } bits; +}; + +struct dc_plane_cm { + struct kref refcount; + struct dc_transfer_func shaper_func; + union { + struct dc_3dlut lut3d_func; + struct dc_3dlut_dma lut3d_dma; + }; + struct dc_transfer_func blend_func; + union dc_plane_cm_flags flags; +}; + /* * This structure is filled in by dc_surface_get_status and contains * the last requested address and the currently active address so the called @@ -1501,47 +1539,120 @@ struct dc_plane_status { struct cm_hist cm_hist; }; -union surface_update_flags { - - struct { - uint32_t addr_update:1; - /* Medium updates */ - uint32_t dcc_change:1; - uint32_t color_space_change:1; - uint32_t horizontal_mirror_change:1; - uint32_t per_pixel_alpha_change:1; - uint32_t global_alpha_change:1; - uint32_t hdr_mult:1; - uint32_t rotation_change:1; - uint32_t swizzle_change:1; - uint32_t scaling_change:1; - uint32_t position_change:1; - uint32_t in_transfer_func_change:1; - uint32_t input_csc_change:1; - uint32_t coeff_reduction_change:1; - uint32_t pixel_format_change:1; - uint32_t plane_size_change:1; - uint32_t gamut_remap_change:1; - uint32_t cursor_csc_color_matrix_change:1; - - /* Full updates */ - uint32_t new_plane:1; - uint32_t bpp_change:1; - uint32_t gamma_change:1; - uint32_t bandwidth_change:1; - uint32_t clock_change:1; - uint32_t stereo_format_change:1; - uint32_t lut_3d:1; - uint32_t tmz_changed:1; - uint32_t mcm_transfer_function_enable_change:1; /* disable or enable MCM transfer func */ - uint32_t full_update:1; - uint32_t sdr_white_level_nits:1; - uint32_t cm_hist_change:1; - } bits; - - uint32_t raw; +struct pipe_update_bits { + uint32_t addr_update:1; + uint32_t dcc_change:1; + uint32_t color_space_change:1; + uint32_t horizontal_mirror_change:1; + uint32_t per_pixel_alpha_change:1; + uint32_t global_alpha_change:1; + uint32_t hdr_mult:1; + uint32_t rotation_change:1; + uint32_t swizzle_change:1; + uint32_t scaling_change:1; + uint32_t position_change:1; + uint32_t in_transfer_func_change:1; + uint32_t input_csc_change:1; + uint32_t coeff_reduction_change:1; + uint32_t pixel_format_change:1; + uint32_t plane_size_change:1; + uint32_t gamut_remap_change:1; + uint32_t cursor_csc_color_matrix_change:1; + uint32_t new_plane:1; + uint32_t bpp_change:1; + uint32_t gamma_change:1; + uint32_t bandwidth_change:1; + uint32_t clock_change:1; + uint32_t stereo_format_change:1; + uint32_t lut_3d:1; + uint32_t tmz_changed:1; + uint32_t mcm_transfer_function_enable_change:1; /* disable or enable MCM transfer func */ + uint32_t full_update:1; + uint32_t sdr_white_level_nits:1; + uint32_t cm_hist_change:1; + /* NOTE: When adding a new field, also update: + * - dc_pipe_update_bits_set_full() + * - dc_pipe_update_bits_is_any_set() + */ }; +static inline void dc_pipe_update_bits_clear(struct pipe_update_bits *flags) +{ + /* memset ensures padding bits are zeroed */ + memset(flags, 0, sizeof(*flags)); +} + +static inline void dc_pipe_update_bits_set_full(struct pipe_update_bits *flags) +{ + dc_pipe_update_bits_clear(flags); + flags->addr_update = 1; + flags->dcc_change = 1; + flags->color_space_change = 1; + flags->horizontal_mirror_change = 1; + flags->per_pixel_alpha_change = 1; + flags->global_alpha_change = 1; + flags->hdr_mult = 1; + flags->rotation_change = 1; + flags->swizzle_change = 1; + flags->scaling_change = 1; + flags->position_change = 1; + flags->in_transfer_func_change = 1; + flags->input_csc_change = 1; + flags->coeff_reduction_change = 1; + flags->pixel_format_change = 1; + flags->plane_size_change = 1; + flags->gamut_remap_change = 1; + flags->cursor_csc_color_matrix_change = 1; + flags->new_plane = 1; + flags->bpp_change = 1; + flags->gamma_change = 1; + flags->bandwidth_change = 1; + flags->clock_change = 1; + flags->stereo_format_change = 1; + flags->lut_3d = 1; + flags->tmz_changed = 1; + flags->mcm_transfer_function_enable_change = 1; + flags->full_update = 1; + flags->sdr_white_level_nits = 1; + flags->cm_hist_change = 1; +} + +static inline bool dc_pipe_update_bits_is_any_set(const struct pipe_update_bits *flags) +{ + return flags->addr_update || + flags->dcc_change || + flags->color_space_change || + flags->horizontal_mirror_change || + flags->per_pixel_alpha_change || + flags->global_alpha_change || + flags->hdr_mult || + flags->rotation_change || + flags->swizzle_change || + flags->scaling_change || + flags->position_change || + flags->in_transfer_func_change || + flags->input_csc_change || + flags->coeff_reduction_change || + flags->pixel_format_change || + flags->plane_size_change || + flags->gamut_remap_change || + flags->cursor_csc_color_matrix_change || + flags->new_plane || + flags->bpp_change || + flags->gamma_change || + flags->bandwidth_change || + flags->clock_change || + flags->stereo_format_change || + flags->lut_3d || + flags->tmz_changed || + flags->mcm_transfer_function_enable_change || + flags->full_update || + flags->sdr_white_level_nits || + flags->cm_hist_change; +} + +bool dc_check_address_only_update(struct pipe_update_bits update_bits); + #define DC_REMOVE_PLANE_POINTERS 1 struct dc_plane_state { @@ -1566,14 +1677,22 @@ struct dc_plane_state { struct fixed31_32 hdr_mult; struct colorspace_transform gamut_remap_matrix; + enum dc_color_space color_space; + +#ifndef TRIM_CM2 // TODO: No longer used, remove struct dc_hdr_static_metadata hdr_static_ctx; - enum dc_color_space color_space; - struct dc_3dlut lut3d_func; struct dc_transfer_func in_shaper_func; struct dc_transfer_func blend_tf; + enum dc_cm2_shaper_3dlut_setting mcm_shaper_3dlut_setting; + bool mcm_lut1d_enable; + struct dc_cm2_func_luts mcm_luts; +#endif /* TRIM_CM2 */ + bool lut_bank_a; + enum mpcc_movable_cm_location mcm_location; + struct dc_plane_cm cm; struct dc_transfer_func *gamcor_tf; enum surface_pixel_format format; @@ -1590,7 +1709,7 @@ struct dc_plane_state { bool horizontal_mirror; unsigned int layer_index; - union surface_update_flags update_flags; + struct pipe_update_bits update_bits; bool flip_int_enabled; bool skip_manual_trigger; @@ -1610,11 +1729,6 @@ struct dc_plane_state { bool is_statically_allocated; enum chroma_cositing cositing; - enum dc_cm2_shaper_3dlut_setting mcm_shaper_3dlut_setting; - bool mcm_lut1d_enable; - struct dc_cm2_func_luts mcm_luts; - bool lut_bank_a; - enum mpcc_movable_cm_location mcm_location; struct dc_csc_transform cursor_csc_color_matrix; bool adaptive_sharpness_en; int adaptive_sharpness_policy; @@ -1728,6 +1842,10 @@ struct dc_scratch_space { * of ddc_pin to know which aux instance is associated with link. */ bool no_ddc_pin; + /** When set, forces all native I2C communication on this DP connector + * to use the I2C-over-AUX protocol instead of native I2C signaling. + */ + bool force_to_use_aux; enum gpio_ddc_line aux_hw_inst; enum gpio_ddc_line ddc_hw_inst; @@ -1978,17 +2096,7 @@ struct dc_surface_update { const struct dc_csc_transform *input_csc_color_matrix; const struct fixed31_32 *coeff_reduction_factor; - const struct dc_transfer_func *func_shaper; - const struct dc_3dlut *lut3d_func; - const struct dc_transfer_func *blend_tf; const struct colorspace_transform *gamut_remap_matrix; - /* - * Color Transformations for pre-blend MCM (Shaper, 3DLUT, 1DLUT) - * - * change cm2_params.component_settings: Full update - * change cm2_params.cm2_luts: Fast update - */ - const struct dc_cm2_parameters *cm2_params; const struct dc_plane_cm *cm; const struct dc_csc_transform *cursor_csc_color_matrix; unsigned int sdr_white_level_nits; @@ -2034,6 +2142,10 @@ struct dc_3dlut *dc_create_3dlut_func(void); void dc_3dlut_func_release(struct dc_3dlut *lut); void dc_3dlut_func_retain(struct dc_3dlut *lut); +struct dc_plane_cm *dc_plane_cm_create(void); +void dc_plane_cm_release(struct dc_plane_cm *cm); +void dc_plane_cm_retain(struct dc_plane_cm *cm); + void dc_post_update_surfaces_to_stream( struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 0ee5c0c5545c..68ed0e16639d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -518,9 +518,6 @@ void dc_dmub_srv_query_caps_cmd(struct dc_dmub_srv *dc_dmub_srv) { union dmub_rb_cmd cmd = { 0 }; - if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation) - return; - memset(&cmd, 0, sizeof(cmd)); /* Prepare fw command */ @@ -1302,9 +1299,6 @@ bool dc_dmub_srv_is_hw_pwr_up(struct dc_dmub_srv *dc_dmub_srv, bool wait) if (!dc_dmub_srv || !dc_dmub_srv->dmub) return true; - if (dc_dmub_srv->ctx->dc->debug.dmcub_emulation) - return true; - dc_ctx = dc_dmub_srv->ctx; if (wait) { @@ -1345,9 +1339,6 @@ static void dc_dmub_srv_notify_idle(const struct dc *dc, bool allow_idle) struct dc_dmub_srv *dc_dmub_srv; union dmub_rb_cmd cmd = {0}; - if (dc->debug.dmcub_emulation) - return; - if (!dc->ctx->dmub_srv || !dc->ctx->dmub_srv->dmub) return; @@ -1466,9 +1457,6 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc) struct dc_dmub_srv *dc_dmub_srv; uint32_t rcg_exit_count = 0, ips1_exit_count = 0, ips2_exit_count = 0, ips1z8_exit_count = 0; - if (dc->debug.dmcub_emulation) - return; - if (!dc->ctx->dmub_srv || !dc->ctx->dmub_srv->dmub) return; @@ -2137,9 +2125,7 @@ bool dmub_lsdma_init(struct dc_dmub_srv *dc_dmub_srv) bool dmub_lsdma_send_linear_copy_command( struct dc_dmub_srv *dc_dmub_srv, - uint64_t src_addr, - uint64_t dst_addr, - uint32_t count + struct lsdma_linear_copy_params copy_data ) { struct dc_context *dc_ctx = dc_dmub_srv->ctx; @@ -2154,11 +2140,20 @@ bool dmub_lsdma_send_linear_copy_command( cmd.cmd_common.header.sub_type = DMUB_CMD__LSDMA_LINEAR_COPY; wait_type = DM_DMUB_WAIT_TYPE_NO_WAIT; - lsdma_data->u.linear_copy_data.count = count - 1; // LSDMA controller expects bytes to copy -1 - lsdma_data->u.linear_copy_data.src_lo = src_addr & 0xFFFFFFFF; - lsdma_data->u.linear_copy_data.src_hi = (src_addr >> 32) & 0xFFFFFFFF; - lsdma_data->u.linear_copy_data.dst_lo = dst_addr & 0xFFFFFFFF; - lsdma_data->u.linear_copy_data.dst_hi = (dst_addr >> 32) & 0xFFFFFFFF; + lsdma_data->u.linear_copy_data.count = copy_data.count; + lsdma_data->u.linear_copy_data.src_lo = copy_data.src_lo; + lsdma_data->u.linear_copy_data.src_hi = copy_data.src_hi; + lsdma_data->u.linear_copy_data.dst_lo = copy_data.dst_lo; + lsdma_data->u.linear_copy_data.dst_hi = copy_data.dst_hi; + lsdma_data->u.linear_copy_data.tmz = copy_data.tmz; + lsdma_data->u.linear_copy_data.data_format = copy_data.data_format; + lsdma_data->u.linear_copy_data.num_type = copy_data.num_type; + lsdma_data->u.linear_copy_data.read_compress = copy_data.read_compress; + lsdma_data->u.linear_copy_data.write_compress = copy_data.write_compress; + lsdma_data->u.linear_copy_data.max_com = copy_data.max_com; + lsdma_data->u.linear_copy_data.max_uncom = copy_data.max_uncom; + lsdma_data->u.linear_copy_data.cache_policy_src = copy_data.cache_policy_src; + lsdma_data->u.linear_copy_data.cache_policy_dst = copy_data.cache_policy_dst; result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); @@ -2203,6 +2198,12 @@ bool dmub_lsdma_send_linear_sub_window_copy_command( lsdma_data->u.linear_sub_window_copy_data.rect_y = copy_data.rect_y; lsdma_data->u.linear_sub_window_copy_data.src_cache_policy = copy_data.src_cache_policy; lsdma_data->u.linear_sub_window_copy_data.dst_cache_policy = copy_data.dst_cache_policy; + lsdma_data->u.linear_sub_window_copy_data.data_format = copy_data.data_format; + lsdma_data->u.linear_sub_window_copy_data.num_type = copy_data.num_type; + lsdma_data->u.linear_sub_window_copy_data.read_compress = copy_data.read_compress; + lsdma_data->u.linear_sub_window_copy_data.write_compress = copy_data.write_compress; + lsdma_data->u.linear_sub_window_copy_data.max_com = copy_data.max_com; + lsdma_data->u.linear_sub_window_copy_data.max_uncom = copy_data.max_uncom; result = dc_wake_and_execute_dmub_cmd(dc_ctx, &cmd, wait_type); diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index ebcaf49e5961..8bdaac0b0f98 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -37,17 +37,8 @@ struct dc_crtc_timing; struct dc_state; struct dc_surface_update; -struct dc_reg_helper_state { - bool gather_in_progress; - uint32_t same_addr_count; - bool should_burst_write; - union dmub_rb_cmd cmd_data; - unsigned int reg_seq_count; -}; - struct dc_dmub_srv { struct dmub_srv *dmub; - struct dc_reg_helper_state reg_helper_offload; struct dc_context *ctx; void *dm; @@ -212,11 +203,31 @@ void dc_dmub_srv_fams2_passthrough_flip( int surface_count); bool dmub_lsdma_init(struct dc_dmub_srv *dc_dmub_srv); + +struct lsdma_linear_copy_params { + uint32_t src_lo; + uint32_t src_hi; + + uint32_t dst_lo; + uint32_t dst_hi; + + uint32_t count : 30; + uint32_t read_compress : 2; + + uint32_t tmz : 4; + uint32_t cache_policy_src : 3; + uint32_t cache_policy_dst : 3; + uint32_t data_format : 6; + uint32_t num_type : 3; + uint32_t write_compress : 2; + uint32_t max_com : 2; + uint32_t max_uncom : 1; + uint32_t reserved0 : 8; +}; + bool dmub_lsdma_send_linear_copy_command( struct dc_dmub_srv *dc_dmub_srv, - uint64_t src_addr, - uint64_t dst_addr, - uint32_t count); + struct lsdma_linear_copy_params copy_data); struct lsdma_linear_sub_window_copy_params { uint32_t src_lo; @@ -244,7 +255,13 @@ struct lsdma_linear_sub_window_copy_params { uint32_t element_size : 3; uint32_t src_cache_policy : 3; uint32_t dst_cache_policy : 3; - uint32_t padding : 19; + uint32_t data_format : 6; + uint32_t num_type : 3; + uint32_t read_compress : 2; + uint32_t write_compress : 2; + uint32_t max_com : 2; + uint32_t max_uncom : 1; + uint32_t reserved0 : 3; }; bool dmub_lsdma_send_linear_sub_window_copy_command( diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index fbef0dc743ff..d0ba9ad67a3e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1146,6 +1146,7 @@ struct edp_psr_info { union edp_psr_dpcd_caps psr_dpcd_caps; uint8_t psr2_su_y_granularity_cap; uint8_t force_psrsu_cap; + uint8_t psr_active_vtotal_control_cap; }; struct replay_info { diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c index 0e0165764a57..cc7fea613d9e 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_helper.c +++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c @@ -39,53 +39,6 @@ #define DC_LOGGER \ ctx->logger -static inline void submit_dmub_read_modify_write( - struct dc_reg_helper_state *offload, - const struct dc_context *ctx) -{ - struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; - - offload->should_burst_write = - (offload->same_addr_count == (DMUB_READ_MODIFY_WRITE_SEQ__MAX - 1)); - cmd_buf->header.payload_bytes = - sizeof(struct dmub_cmd_read_modify_write_sequence) * offload->reg_seq_count; - - dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); - - memset(cmd_buf, 0, sizeof(*cmd_buf)); - - offload->reg_seq_count = 0; - offload->same_addr_count = 0; -} - -static inline void submit_dmub_burst_write( - struct dc_reg_helper_state *offload, - const struct dc_context *ctx) -{ - struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; - - cmd_buf->header.payload_bytes = - sizeof(uint32_t) * offload->reg_seq_count; - - dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); - - memset(cmd_buf, 0, sizeof(*cmd_buf)); - - offload->reg_seq_count = 0; -} - -static inline void submit_dmub_reg_wait( - struct dc_reg_helper_state *offload, - const struct dc_context *ctx) -{ - struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; - - dc_wake_and_execute_dmub_cmd(ctx, &offload->cmd_data, DM_DMUB_WAIT_TYPE_NO_WAIT); - - memset(cmd_buf, 0, sizeof(*cmd_buf)); - offload->reg_seq_count = 0; -} - struct dc_reg_value_masks { uint32_t value; uint32_t mask; @@ -127,98 +80,6 @@ static void set_reg_field_values(struct dc_reg_value_masks *field_value_mask, } } -static void dmub_flush_buffer_execute( - struct dc_reg_helper_state *offload, - const struct dc_context *ctx) -{ - submit_dmub_read_modify_write(offload, ctx); -} - -static void dmub_flush_burst_write_buffer_execute( - struct dc_reg_helper_state *offload, - const struct dc_context *ctx) -{ - submit_dmub_burst_write(offload, ctx); -} - -static bool dmub_reg_value_burst_set_pack(const struct dc_context *ctx, uint32_t addr, - uint32_t reg_val) -{ - struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; - struct dmub_rb_cmd_burst_write *cmd_buf = &offload->cmd_data.burst_write; - - /* flush command if buffer is full */ - if (offload->reg_seq_count == DMUB_BURST_WRITE_VALUES__MAX) - dmub_flush_burst_write_buffer_execute(offload, ctx); - - if (offload->cmd_data.cmd_common.header.type == DMUB_CMD__REG_SEQ_BURST_WRITE && - addr != cmd_buf->addr) { - dmub_flush_burst_write_buffer_execute(offload, ctx); - return false; - } - - cmd_buf->header.type = DMUB_CMD__REG_SEQ_BURST_WRITE; - cmd_buf->header.sub_type = 0; - cmd_buf->addr = addr; - cmd_buf->write_values[offload->reg_seq_count] = reg_val; - offload->reg_seq_count++; - - return true; -} - -static uint32_t dmub_reg_value_pack(const struct dc_context *ctx, uint32_t addr, - struct dc_reg_value_masks *field_value_mask) -{ - struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; - struct dmub_rb_cmd_read_modify_write *cmd_buf = &offload->cmd_data.read_modify_write; - struct dmub_cmd_read_modify_write_sequence *seq; - - /* flush command if buffer is full */ - if (offload->cmd_data.cmd_common.header.type != DMUB_CMD__REG_SEQ_BURST_WRITE && - offload->reg_seq_count == DMUB_READ_MODIFY_WRITE_SEQ__MAX) - dmub_flush_buffer_execute(offload, ctx); - - if (offload->should_burst_write) { - if (dmub_reg_value_burst_set_pack(ctx, addr, field_value_mask->value)) - return field_value_mask->value; - else - offload->should_burst_write = false; - } - - /* pack commands */ - cmd_buf->header.type = DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE; - cmd_buf->header.sub_type = 0; - seq = &cmd_buf->seq[offload->reg_seq_count]; - - if (offload->reg_seq_count) { - if (cmd_buf->seq[offload->reg_seq_count - 1].addr == addr) - offload->same_addr_count++; - else - offload->same_addr_count = 0; - } - - seq->addr = addr; - seq->modify_mask = field_value_mask->mask; - seq->modify_value = field_value_mask->value; - offload->reg_seq_count++; - - return field_value_mask->value; -} - -static void dmub_reg_wait_done_pack(const struct dc_context *ctx, uint32_t addr, - uint32_t mask, uint32_t shift, uint32_t condition_value, uint32_t time_out_us) -{ - struct dc_reg_helper_state *offload = &ctx->dmub_srv->reg_helper_offload; - struct dmub_rb_cmd_reg_wait *cmd_buf = &offload->cmd_data.reg_wait; - - cmd_buf->header.type = DMUB_CMD__REG_REG_WAIT; - cmd_buf->header.sub_type = 0; - cmd_buf->reg_wait.addr = addr; - cmd_buf->reg_wait.condition_field_value = mask & (condition_value << shift); - cmd_buf->reg_wait.mask = mask; - cmd_buf->reg_wait.time_out_us = time_out_us; -} - uint32_t generic_reg_update_ex(const struct dc_context *ctx, uint32_t addr, int n, uint8_t shift1, uint32_t mask1, uint32_t field_value1, @@ -235,11 +96,6 @@ uint32_t generic_reg_update_ex(const struct dc_context *ctx, va_end(ap); - if (ctx->dmub_srv && - ctx->dmub_srv->reg_helper_offload.gather_in_progress) - return dmub_reg_value_pack(ctx, addr, &field_value_mask); - /* todo: return void so we can decouple code running in driver from register states */ - /* mmio write directly */ reg_val = dm_read_reg(ctx, addr); reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; @@ -265,12 +121,6 @@ uint32_t generic_reg_set_ex(const struct dc_context *ctx, /* mmio write directly */ reg_val = (reg_val & ~field_value_mask.mask) | field_value_mask.value; - if (ctx->dmub_srv && - ctx->dmub_srv->reg_helper_offload.gather_in_progress) { - return dmub_reg_value_burst_set_pack(ctx, addr, reg_val); - /* todo: return void so we can decouple code running in driver from register states */ - } - dm_write_reg(ctx, addr, reg_val); return reg_val; } @@ -434,13 +284,6 @@ void generic_reg_wait(const struct dc_context *ctx, uint32_t reg_val; unsigned int i; - if (ctx->dmub_srv && - ctx->dmub_srv->reg_helper_offload.gather_in_progress) { - dmub_reg_wait_done_pack(ctx, addr, mask, shift, condition_value, - delay_between_poll_us * time_out_num_tries); - return; - } - /* * Something is terribly wrong if time out is > 3000ms. * 3000ms is the maximum time needed for SMU to pass values back. @@ -491,12 +334,6 @@ uint32_t generic_read_indirect_reg(const struct dc_context *ctx, { uint32_t value = 0; - // when reg read, there should not be any offload. - if (ctx->dmub_srv && - ctx->dmub_srv->reg_helper_offload.gather_in_progress) { - ASSERT(false); - } - dm_write_reg(ctx, addr_index, index); value = dm_read_reg(ctx, addr_data); @@ -624,69 +461,6 @@ uint32_t generic_indirect_reg_get_sync(const struct dc_context *ctx, return value; } -void reg_sequence_start_gather(const struct dc_context *ctx) -{ - /* if reg sequence is supported and enabled, set flag to - * indicate we want to have REG_SET, REG_UPDATE macro build - * reg sequence command buffer rather than MMIO directly. - */ - - if (ctx->dmub_srv && ctx->dc->debug.dmub_offload_enabled) { - struct dc_reg_helper_state *offload = - &ctx->dmub_srv->reg_helper_offload; - - /* caller sequence mismatch. need to debug caller. offload will not work!!! */ - ASSERT(!offload->gather_in_progress); - - offload->gather_in_progress = true; - } -} - -void reg_sequence_start_execute(const struct dc_context *ctx) -{ - struct dc_reg_helper_state *offload; - - if (!ctx->dmub_srv) - return; - - offload = &ctx->dmub_srv->reg_helper_offload; - - if (offload && offload->gather_in_progress) { - offload->gather_in_progress = false; - offload->should_burst_write = false; - switch (offload->cmd_data.cmd_common.header.type) { - case DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE: - submit_dmub_read_modify_write(offload, ctx); - break; - case DMUB_CMD__REG_REG_WAIT: - submit_dmub_reg_wait(offload, ctx); - break; - case DMUB_CMD__REG_SEQ_BURST_WRITE: - submit_dmub_burst_write(offload, ctx); - break; - default: - return; - } - } -} - -void reg_sequence_wait_done(const struct dc_context *ctx) -{ - /* callback to DM to poll for last submission done*/ - struct dc_reg_helper_state *offload; - - if (!ctx->dmub_srv) - return; - - offload = &ctx->dmub_srv->reg_helper_offload; - - if (offload && - ctx->dc->debug.dmub_offload_enabled && - !ctx->dc->debug.dmcub_emulation) { - dc_dmub_srv_wait_for_idle(ctx->dmub_srv, DM_DMUB_WAIT_TYPE_WAIT, NULL); - } -} - char *dce_version_to_string(const int version) { switch (version) { diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h index 4154cd059562..8b164edc9c51 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_stream.h +++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h @@ -128,6 +128,35 @@ union stream_update_flags { uint32_t raw; }; +static inline void stream_update_flags_clear(union stream_update_flags *flags) +{ + flags->raw = 0; +} + +static inline void stream_update_flags_set_full(union stream_update_flags *flags) +{ + stream_update_flags_clear(flags); + flags->bits.scaling = 1; + flags->bits.out_tf = 1; + flags->bits.out_csc = 1; + flags->bits.abm_level = 1; + flags->bits.dpms_off = 1; + flags->bits.gamut_remap = 1; + flags->bits.wb_update = 1; + flags->bits.dsc_changed = 1; + flags->bits.mst_bw = 1; + flags->bits.crtc_timing_adjust = 1; + flags->bits.fams_changed = 1; + flags->bits.scaler_sharpener = 1; + flags->bits.sharpening_required = 1; + flags->bits.cursor_attr = 1; + flags->bits.cursor_pos = 1; + flags->bits.periodic_interrupt = 1; + flags->bits.info_frame = 1; + flags->bits.dmdata = 1; + flags->bits.dither = 1; +} + struct test_pattern { enum dp_test_pattern type; enum dp_test_pattern_color_space color_space; diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h index 4ed1efa17270..90dd1ae7e953 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_types.h @@ -183,6 +183,7 @@ struct dc_panel_patch { unsigned int force_frl; unsigned int vsdb_rcc_wa; unsigned int delay_hdmi_link_training; + unsigned int skip_frl_pre_training; unsigned int skip_avmute; unsigned int skip_audio_sab_check; unsigned int mst_start_top_delay; @@ -1397,6 +1398,39 @@ enum dc_hpd_enable_select { HPD_EN_FOR_SECONDARY_EDP_ONLY, }; +enum dc_cm_lut_swizzle { + CM_LUT_3D_SWIZZLE_LINEAR_RGB, + CM_LUT_3D_SWIZZLE_LINEAR_BGR, + CM_LUT_1D_PACKED_LINEAR +}; + +enum dc_cm_lut_pixel_format { + CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB, +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) + CM_LUT_PIXEL_FORMAT_BGRA16161616_UNORM_12MSB, +#endif + CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB, +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) + CM_LUT_PIXEL_FORMAT_BGRA16161616_UNORM_12LSB, +#endif + CM_LUT_PIXEL_FORMAT_RGBA16161616_FLOAT_FP1_5_10, +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) + CM_LUT_PIXEL_FORMAT_BGRA16161616_FLOAT_FP1_5_10 +#endif +}; + +enum dc_cm_lut_size { + CM_LUT_SIZE_NONE, + CM_LUT_SIZE_999, + CM_LUT_SIZE_171717, +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) + CM_LUT_SIZE_333333, + CM_LUT_SIZE_454545, + CM_LUT_SIZE_656565, +#endif +}; + +#ifndef TRIM_CM2 enum dc_cm2_shaper_3dlut_setting { DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL, DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER, @@ -1421,6 +1455,16 @@ enum dc_cm2_gpu_mem_format { DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10 }; +enum dc_cm2_gpu_mem_size { + DC_CM2_GPU_MEM_SIZE_171717, + DC_CM2_GPU_MEM_SIZE_333333, + DC_CM2_GPU_MEM_SIZE_454545, + DC_CM2_GPU_MEM_SIZE_656565, + DC_CM2_GPU_MEM_SIZE_TRANSFORMED, +}; +#endif /* TRIM_CM2 */ + +#ifndef TRIM_CM2 struct dc_cm2_gpu_mem_format_parameters { enum dc_cm2_gpu_mem_format format; union { @@ -1432,14 +1476,6 @@ struct dc_cm2_gpu_mem_format_parameters { }; }; -enum dc_cm2_gpu_mem_size { - DC_CM2_GPU_MEM_SIZE_171717, - DC_CM2_GPU_MEM_SIZE_333333, - DC_CM2_GPU_MEM_SIZE_454545, - DC_CM2_GPU_MEM_SIZE_656565, - DC_CM2_GPU_MEM_SIZE_TRANSFORMED, -}; - struct dc_cm2_gpu_mem_parameters { struct dc_plane_address addr; enum dc_cm2_gpu_mem_layout layout; @@ -1448,17 +1484,16 @@ struct dc_cm2_gpu_mem_parameters { enum dc_cm2_gpu_mem_size size; uint16_t bit_depth; }; +#endif /* TRIM_CM2 */ +#ifndef TRIM_CM2 enum dc_cm2_transfer_func_source { DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM, DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM }; +#endif /* TRIM_CM2 */ -struct dc_cm2_component_settings { - enum dc_cm2_shaper_3dlut_setting shaper_3dlut_setting; - bool lut1d_enable; -}; - +#ifndef TRIM_CM2 /* * All pointers in this struct must remain valid for as long as the 3DLUTs are used */ @@ -1478,11 +1513,7 @@ struct dc_cm2_func_luts { } lut3d_data; const struct dc_transfer_func *lut1d_func; }; - -struct dc_cm2_parameters { - struct dc_cm2_component_settings component_settings; - struct dc_cm2_func_luts cm2_luts; -}; +#endif /* TRIM_CM2 */ enum mall_stream_type { SUBVP_NONE, // subvp not in use diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c index e57242f8bc12..616a896f0782 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.c @@ -77,13 +77,26 @@ void dccg42_otg_drop_pixel(struct dccg *dccg, } } -void dccg42_enable_global_fgcg(struct dccg *dccg, bool value) +void dccg42_enable_global_fgcg(struct dccg *dccg, bool enable) { struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); - if (dccg->ctx->dc->debug.disable_clock_gate) - value = false; - REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !value); + /* Temporary workaround for IOMMU mismatch issue. + * Fine grain control via bit2 of debug flag. + */ + if (dccg->ctx->dc->debug.disable_clock_gate || (dccg->ctx->dc->debug.iommu_mismatch_temp_wka & 0x4)) + enable = false; + + REG_UPDATE(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, !enable); +} + +bool dccg42_get_global_fgcg_status(struct dccg *dccg) +{ + struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + uint32_t disabled = 0; + + REG_GET(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, &disabled); + return disabled & 0x1; } void dccg42_set_physymclk( @@ -265,40 +278,35 @@ void dccg42_trigger_dio_fifo_resync(struct dccg *dccg) static void dccg42_init(struct dccg *dccg) { - int otg_inst; - struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg); + unsigned int i; + struct resource_pool *res_pool = dccg->ctx->dc->res_pool; /* Set HPO stream encoder to use refclk to avoid case where PHY is * disabled and SYMCLK32 for HPO SE is sourced from PHYD32CLK which * will cause DCN to hang. */ - for (otg_inst = 0; otg_inst < 4; otg_inst++) - dccg35_disable_symclk32_se(dccg, otg_inst); + for (i = 0; i < res_pool->hpo_dp_stream_enc_count; i++) + dccg35_disable_symclk32_se(dccg, i); if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le) { - dccg401_disable_symclk32_le(dccg, 0); - dccg401_disable_symclk32_le(dccg, 1); - dccg401_disable_symclk32_le(dccg, 2); - dccg401_disable_symclk32_le(dccg, 3); + for (i = 0; i < res_pool->hpo_dp_link_enc_count; i++) + dccg401_disable_symclk32_le(dccg, i); } if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream) { - dccg401_disable_dpstreamclk(dccg, 0); - dccg401_disable_dpstreamclk(dccg, 1); - dccg401_disable_dpstreamclk(dccg, 2); - dccg401_disable_dpstreamclk(dccg, 3); - } - if (!dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk) { - REG_UPDATE_5(DCCG_GATE_DISABLE_CNTL2, - PHYASYMCLK_ROOT_GATE_DISABLE, 1, - PHYBSYMCLK_ROOT_GATE_DISABLE, 1, - PHYCSYMCLK_ROOT_GATE_DISABLE, 1, - PHYDSYMCLK_ROOT_GATE_DISABLE, 1, - PHYESYMCLK_ROOT_GATE_DISABLE, 1); + for (i = 0; i < res_pool->hpo_dp_stream_enc_count; i++) + dccg401_disable_dpstreamclk(dccg, i); } + dccg42_disable_hdmistreamclk(dccg); if (dccg->ctx->dc->debug.root_clock_optimization.bits.hdmichar) dccg42_disable_hdmicharclk(dccg, 0); + + if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) { + for (i = 0; i < res_pool->pipe_count; i++) { + dccg35_dpp_root_clock_control(dccg, i, true); + } + } } @@ -340,7 +348,8 @@ static const struct dccg_funcs dccg42_funcs = { .dccg_root_gate_disable_control = dccg35_root_gate_disable_control, .dccg_read_reg_state = dccg31_read_reg_state, .dccg_enable_global_fgcg = dccg42_enable_global_fgcg, - .allow_clock_gating = dccg2_allow_clock_gating + .allow_clock_gating = dccg2_allow_clock_gating, + .dccg_get_global_fgcg_status = dccg42_get_global_fgcg_status, }; struct dccg *dccg42_create( diff --git a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h index 2076565b1caa..ebd3cec1a977 100644 --- a/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h +++ b/drivers/gpu/drm/amd/display/dc/dccg/dcn42/dcn42_dccg.h @@ -46,6 +46,7 @@ DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_STATE, mask_sh),\ DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DCCG_FIFO_ERRDET_OVR_EN, mask_sh),\ DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, DISPCLK_CHG_FWD_CORR_DISABLE, mask_sh),\ + DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, mask_sh),\ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(DPPCLK0_DTO_PARAM, DPPCLK0_DTO_MODULO, mask_sh),\ DCCG_SF(HDMICHARCLK0_CLOCK_CNTL, HDMICHARCLK0_EN, mask_sh),\ @@ -56,34 +57,24 @@ DCCG_SF(PHYBSYMCLK_CLOCK_CNTL, PHYBSYMCLK_SRC_SEL, mask_sh),\ DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_EN, mask_sh),\ DCCG_SF(PHYCSYMCLK_CLOCK_CNTL, PHYCSYMCLK_SRC_SEL, mask_sh),\ - DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_EN, mask_sh),\ - DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_SRC_SEL, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK0_EN, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK1_EN, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_EN, mask_sh),\ - DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_EN, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK0_SRC_SEL, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK1_SRC_SEL, mask_sh),\ DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK2_SRC_SEL, mask_sh),\ - DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_SRC_SEL, mask_sh),\ DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_EN, mask_sh),\ DCCG_SF(HDMISTREAMCLK_CNTL, HDMISTREAMCLK0_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_SRC_SEL, mask_sh),\ - DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE0_EN, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE1_EN, mask_sh),\ DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE2_EN, mask_sh),\ - DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_EN, mask_sh),\ DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_SRC_SEL, mask_sh),\ - DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE2_SRC_SEL, mask_sh),\ - DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE3_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE0_EN, mask_sh),\ DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE1_EN, mask_sh),\ - DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE2_EN, mask_sh),\ - DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE3_EN, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 0, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 1, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, PIPE, DTO_SRC_SEL, 2, mask_sh),\ @@ -121,7 +112,6 @@ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GLOBAL_FGCG_REP_CNTL, DCCG_GLOBAL_FGCG_REP_DIS, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 0, mask_sh),\ DCCG_SFII(OTG, PIXEL_RATE_CNTL, DP_DTO, ENABLE, 1, mask_sh),\ @@ -134,7 +124,6 @@ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_EN, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_EN, mask_sh),\ DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_EN, mask_sh),\ - DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_EN, mask_sh),\ DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(DSCCLK0_DTO_PARAM, DSCCLK0_DTO_MODULO, mask_sh),\ DCCG_SF(DSCCLK1_DTO_PARAM, DSCCLK1_DTO_PHASE, mask_sh),\ @@ -147,36 +136,26 @@ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKA_FE_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKB_FE_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKC_FE_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKD_FE_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKA_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKB_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKC_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKD_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE1_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE2_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE1_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE2_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE3_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE1_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE2_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE3_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE1_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE2_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE3_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL4, HDMICHARCLK0_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYA_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYB_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYC_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYD_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P1_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DTBCLK_P2_GATE_DISABLE, mask_sh),\ @@ -184,19 +163,15 @@ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_FE_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_FE_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_FE_ROOT_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKA_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKB_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKC_ROOT_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_ROOT_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK0_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK1_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK2_GATE_DISABLE, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK0_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK1_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL6, DSCCLK2_ROOT_GATE_DISABLE, mask_sh),\ @@ -208,26 +183,38 @@ DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_CLOCK_ENABLE, mask_sh),\ DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_CLOCK_ENABLE, mask_sh),\ DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_CLOCK_ENABLE, mask_sh),\ - DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_CLOCK_ENABLE, mask_sh),\ DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_EN, mask_sh),\ DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_EN, mask_sh),\ DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_EN, mask_sh),\ - DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_EN, mask_sh),\ DCCG_SF(SYMCLKA_CLOCK_ENABLE, SYMCLKA_FE_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_FE_SRC_SEL, mask_sh),\ - DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_SRC_SEL, mask_sh),\ - DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_SRC_SEL, mask_sh) + DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_FE_SRC_SEL, mask_sh) #define DCCG_MASK_SH_LIST_DCN42(mask_sh) \ DCCG_MASK_SH_LIST_DCN42_COMMON(mask_sh),\ + DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_EN, mask_sh),\ + DCCG_SF(PHYDSYMCLK_CLOCK_CNTL, PHYDSYMCLK_SRC_SEL, mask_sh),\ DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_EN, mask_sh),\ DCCG_SF(PHYESYMCLK_CLOCK_CNTL, PHYESYMCLK_SRC_SEL, mask_sh),\ DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_PHASE, mask_sh),\ DCCG_SF(HDMISTREAMCLK0_DTO_PARAM, HDMISTREAMCLK0_DTO_MODULO, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKD_FE_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL2, SYMCLKD_GATE_DISABLE, mask_sh),\ DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_PHASE, mask_sh),\ DCCG_SF(DSCCLK3_DTO_PARAM, DSCCLK3_DTO_MODULO, mask_sh),\ - DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_LE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_SE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE2_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_LE3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_FE_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKD_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_ROOT_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL5, DPSTREAMCLK3_GATE_DISABLE, mask_sh),\ + DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYD_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL4, PHYE_REFCLK_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_FE_ROOT_GATE_DISABLE, mask_sh),\ DCCG_SF(DCCG_GATE_DISABLE_CNTL5, SYMCLKE_ROOT_GATE_DISABLE, mask_sh),\ @@ -236,11 +223,22 @@ DCCG_SF(SYMCLKB_CLOCK_ENABLE, SYMCLKB_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKC_CLOCK_ENABLE, SYMCLKC_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_CLOCK_ENABLE, mask_sh),\ + DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_EN, mask_sh),\ + DCCG_SF(SYMCLKD_CLOCK_ENABLE, SYMCLKD_FE_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_SRC_SEL, mask_sh),\ DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_CLOCK_ENABLE, mask_sh),\ DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_EN, mask_sh),\ DCCG_SF(SYMCLKE_CLOCK_ENABLE, SYMCLKE_FE_SRC_SEL, mask_sh),\ - DCCG_SF(DISPCLK_FREQ_CHANGE_CNTL, RESYNC_FIFO_LEVEL_ADJUST_EN, mask_sh) + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_SE_CNTL, SYMCLK32_SE3_EN, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE2_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE3_SRC_SEL, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE2_EN, mask_sh),\ + DCCG_SF(SYMCLK32_LE_CNTL, SYMCLK32_LE3_EN, mask_sh),\ + DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_EN, mask_sh),\ + DCCG_SF(DPSTREAMCLK_CNTL, DPSTREAMCLK3_SRC_SEL, mask_sh),\ + DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK3_EN, mask_sh) void dccg42_otg_add_pixel(struct dccg *dccg, @@ -249,6 +247,7 @@ void dccg42_otg_add_pixel(struct dccg *dccg, void dccg42_otg_drop_pixel(struct dccg *dccg, uint32_t otg_inst); void dccg42_enable_global_fgcg(struct dccg *dccg, bool value); +bool dccg42_get_global_fgcg_status(struct dccg *dccg); void dccg42_set_physymclk( struct dccg *dccg, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c index 72ad3ee3d6a5..6cb5e8152cf1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c @@ -26,6 +26,7 @@ #include "dm_services.h" #include "core_types.h" #include "dce_aux.h" +#include "dce/dce_11_0_d.h" #include "dce/dce_11_0_sh_mask.h" #include "dm_event_log.h" #include "dm_helpers.h" @@ -529,7 +530,7 @@ static uint32_t dce_aux_configure_timeout(struct ddc_service *ddc, uint32_t prev_timeout_val = 0; struct ddc *ddc_pin = ddc->ddc_pin; - if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) + if (ddc->link->force_to_use_aux) return dce_aux_configure_timeout_without_ddc_pin(ddc, timeout_in_us); struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; @@ -652,7 +653,7 @@ int dce_aux_transfer_raw(struct ddc_service *ddc, struct aux_payload *payload, enum aux_return_code_type *operation_result) { - if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) { + if (ddc->link->force_to_use_aux) { /* Check whether aux to be processed via dmub or dcn directly */ if (ddc->ctx->dc->debug.enable_dmub_aux_for_legacy_ddc) { return dce_aux_transfer_dmub_raw(ddc, payload, operation_result); @@ -795,7 +796,7 @@ int dce_aux_transfer_dmub_raw(struct ddc_service *ddc, release_engine(aux_engine); } - if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) { + if (ddc->link->force_to_use_aux) { struct dce_aux *aux_engine = ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]; if (!acquire_aux_engine_without_ddc_pin(aux_engine, ddc_pin)) { @@ -893,7 +894,7 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc, aux110 = FROM_AUX_ENGINE(aux_engine); } - if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) { + if (ddc->link->force_to_use_aux) { aux_engine = ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]; aux110 = FROM_AUX_ENGINE(aux_engine); } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index ed407e779c12..2c3a20d35fe9 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -271,7 +271,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute( bool use_vsc_sdp_for_colorimetry, uint32_t enable_sdp_splitting) { - (void)use_vsc_sdp_for_colorimetry; (void)enable_sdp_splitting; uint32_t h_active_start; uint32_t v_active_start; @@ -334,6 +333,16 @@ static void dce110_stream_encoder_dp_set_stream_attribute( if (REG(DP_MSA_MISC)) misc1 = REG_READ(DP_MSA_MISC); + /* For YCbCr420 and BT2020 Colorimetry Formats, VSC SDP shall be used. + * When MISC1, bit 6, is Set to 1, a Source device uses a VSC SDP to indicate the + * Pixel Encoding/Colorimetry Format and that a Sink device shall ignore MISC1, bit 7, + * and MISC0, bits 7:1 (MISC1, bit 7, and MISC0, bits 7:1, become "don't care"). + */ + if (use_vsc_sdp_for_colorimetry) + misc1 = misc1 | 0x40; + else + misc1 = misc1 & ~0x40; + /* set color depth */ switch (hw_crtc_timing.display_color_depth) { @@ -499,6 +508,10 @@ static void dce110_stream_encoder_dp_set_stream_attribute( hw_crtc_timing.h_addressable + hw_crtc_timing.h_border_right, DP_MSA_VHEIGHT, hw_crtc_timing.v_border_top + hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom); + } else { + /* DCE-only path */ + if (REG(DP_MSA_MISC)) + REG_WRITE(DP_MSA_MISC, misc1); /* MSA_MISC1 */ } } diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h index 342c0afe6a94..88d6044904d1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h @@ -96,7 +96,8 @@ #define SE_COMMON_REG_LIST(id)\ SE_COMMON_REG_LIST_DCE_BASE(id), \ - SRI(AFMT_CNTL, DIG, id) + SRI(AFMT_CNTL, DIG, id), \ + SRI(DP_MSA_MISC, DP, id) #define SE_DCN_REG_LIST(id)\ SE_COMMON_REG_LIST_BASE(id),\ diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c index 9be578ff8c88..140c66081492 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c @@ -27,8 +27,6 @@ #include "dce/dce_11_0_d.h" #include "dce/dce_11_0_sh_mask.h" -#include "gmc/gmc_8_2_sh_mask.h" -#include "gmc/gmc_8_2_d.h" #include "include/logger_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c index b265a72eeb70..095869912c09 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c @@ -27,8 +27,6 @@ #include "dce/dce_11_0_d.h" #include "dce/dce_11_0_sh_mask.h" /* TODO: this needs to be looked at, used by Stella's workaround*/ -#include "gmc/gmc_8_2_d.h" -#include "gmc/gmc_8_2_sh_mask.h" #include "include/logger_interface.h" #include "inc/dce_calcs.h" diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c index fe97d3946cab..4b273762f07a 100644 --- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c +++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c @@ -27,8 +27,12 @@ #include "dce/dce_11_2_d.h" #include "dce/dce_11_2_sh_mask.h" -#include "gmc/gmc_8_1_sh_mask.h" -#include "gmc/gmc_8_1_d.h" + +#ifndef mmGMCON_LPT_TARGET +#define mmGMCON_LPT_TARGET 0x0D53 +#define GMCON_LPT_TARGET__STCTRL_LPT_TARGET__SHIFT 0x00000000 +#define GMCON_LPT_TARGET__STCTRL_LPT_TARGET_MASK 0xffffffffL +#endif #include "include/logger_interface.h" diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c index bfd5515c2f4f..66fe7f313ea3 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c +++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_cm_common.c @@ -303,6 +303,190 @@ bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx, return true; } +/* Linear interpolation of tf_pts entries, where (i >> 4) is the integer tf_pts + * index, (i & 0xf) is the 1/16 sub-position. + */ +static struct fixed31_32 interp_tf_pts(const struct fixed31_32 *output_tf_channel, int i) +{ + struct fixed31_32 in_plus_one, in, value; + uint32_t t = i & 0xf; + + in_plus_one = output_tf_channel[(i >> 4) + 1]; + in = output_tf_channel[i >> 4]; + value = dc_fixpt_sub(in_plus_one, in); + value = dc_fixpt_shr(dc_fixpt_mul_int(value, t), 4); + value = dc_fixpt_add(in, value); + + return value; +} + +bool cm3_helper_translate_curve_to_degamma_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params) +{ + struct curve_points3 *corner_points; + struct pwl_result_data *rgb_resulted; + struct pwl_result_data *rgb; + struct pwl_result_data *rgb_plus_1; + + int32_t region_start, region_end; + int32_t i; + uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; + + if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) + return false; + + corner_points = lut_params->corner_points; + rgb_resulted = lut_params->rgb_resulted; + hw_points = 0; + + memset(lut_params, 0, sizeof(struct pwl_params)); + memset(seg_distr, 0, sizeof(seg_distr)); + + if (output_tf->tf == TRANSFER_FUNCTION_PQ || + output_tf->tf == TRANSFER_FUNCTION_SRGB) { + /* 9 segments + * segments are from 2^-9 to 0 + */ + const uint8_t SEG_COUNT = 9; + seg_distr[0] = 0; // Since we only have one point in darkest region + for (k = 1; k < SEG_COUNT; k++) + seg_distr[k] = k - 1; // 2^(k-1) points per region; halves as k decreases + + region_start = -SEG_COUNT; + region_end = 0; + } else { + /* 12 segments + * segments are from 2^-12 to 2^0 + * There are less than 256 points, for optimization + */ + const uint8_t SEG_COUNT = 12; + + for (i = 0; i < SEG_COUNT; i++) + seg_distr[i] = 4; + + region_start = -SEG_COUNT; + region_end = 0; + } + + for (i = region_end - region_start; i < MAX_REGIONS_NUMBER ; i++) + seg_distr[i] = -1; + + for (k = 0; k < MAX_REGIONS_NUMBER; k++) { + if (seg_distr[k] != -1) + hw_points += (1 << seg_distr[k]); + } + + j = 0; + for (k = 0; k < (region_end - region_start); k++) { + increment = (NUMBER_SW_SEGMENTS << 4) / (1 << seg_distr[k]); + start_index = (region_start + k + MAX_LOW_POINT) * + NUMBER_SW_SEGMENTS; + for (i = (start_index << 4); + i < (start_index << 4) + (NUMBER_SW_SEGMENTS << 4); + i += increment) { + if (j == hw_points - 1) + break; + if ((i >> 4) + 1 >= TRANSFER_FUNC_POINTS) + return false; + + rgb_resulted[j].red = interp_tf_pts(output_tf->tf_pts.red, i); + rgb_resulted[j].green = interp_tf_pts(output_tf->tf_pts.green, i); + rgb_resulted[j].blue = interp_tf_pts(output_tf->tf_pts.blue, i); + j++; + } + } + + /* last point */ + start_index = (region_end + MAX_LOW_POINT) * NUMBER_SW_SEGMENTS; + rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; + rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; + rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; + + corner_points[0].red.x = dc_fixpt_pow(dc_fixpt_from_int(2), + dc_fixpt_from_int(region_start)); + corner_points[0].green.x = corner_points[0].red.x; + corner_points[0].blue.x = corner_points[0].red.x; + corner_points[1].red.x = dc_fixpt_pow(dc_fixpt_from_int(2), + dc_fixpt_from_int(region_end)); + corner_points[1].green.x = corner_points[1].red.x; + corner_points[1].blue.x = corner_points[1].red.x; + + corner_points[0].red.y = rgb_resulted[0].red; + corner_points[0].green.y = rgb_resulted[0].green; + corner_points[0].blue.y = rgb_resulted[0].blue; + + /* see comment above, m_arrPoints[1].y should be the Y value for the + * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) + */ + corner_points[1].red.y = rgb_resulted[hw_points - 1].red; + corner_points[1].green.y = rgb_resulted[hw_points - 1].green; + corner_points[1].blue.y = rgb_resulted[hw_points - 1].blue; + corner_points[1].red.slope = dc_fixpt_zero; + corner_points[1].green.slope = dc_fixpt_zero; + corner_points[1].blue.slope = dc_fixpt_zero; + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* for PQ, we want to have a straight line from last HW X point, + * and the slope to be such that we hit 1.0 at 10000 nits. + */ + const struct fixed31_32 end_value = + dc_fixpt_from_int(125); + + corner_points[1].red.slope = dc_fixpt_div( + dc_fixpt_sub(dc_fixpt_one, corner_points[1].red.y), + dc_fixpt_sub(end_value, corner_points[1].red.x)); + corner_points[1].green.slope = dc_fixpt_div( + dc_fixpt_sub(dc_fixpt_one, corner_points[1].green.y), + dc_fixpt_sub(end_value, corner_points[1].green.x)); + corner_points[1].blue.slope = dc_fixpt_div( + dc_fixpt_sub(dc_fixpt_one, corner_points[1].blue.y), + dc_fixpt_sub(end_value, corner_points[1].blue.x)); + } + + lut_params->hw_points_num = hw_points; + + k = 0; + for (i = 1; i < MAX_REGIONS_NUMBER; i++) { + if (seg_distr[k] != -1) { + lut_params->arr_curve_points[k].segments_num = + seg_distr[k]; + lut_params->arr_curve_points[i].offset = + lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]); + } + k++; + } + + if (seg_distr[k] != -1) + lut_params->arr_curve_points[k].segments_num = seg_distr[k]; + + rgb = rgb_resulted; + rgb_plus_1 = rgb_resulted + 1; + + i = 1; + while (i != hw_points + 1) { + if (dc_fixpt_lt(rgb_plus_1->red, rgb->red)) + rgb_plus_1->red = rgb->red; + if (dc_fixpt_lt(rgb_plus_1->green, rgb->green)) + rgb_plus_1->green = rgb->green; + if (dc_fixpt_lt(rgb_plus_1->blue, rgb->blue)) + rgb_plus_1->blue = rgb->blue; + + rgb->delta_red = dc_fixpt_sub(rgb_plus_1->red, rgb->red); + rgb->delta_green = dc_fixpt_sub(rgb_plus_1->green, rgb->green); + rgb->delta_blue = dc_fixpt_sub(rgb_plus_1->blue, rgb->blue); + + ++rgb_plus_1; + ++rgb; + ++i; + } + cm3_helper_convert_to_custom_float(rgb_resulted, + lut_params->corner_points, + hw_points, false); + + return true; +} + bool cm3_helper_convert_to_custom_float( struct pwl_result_data *rgb_resulted, struct curve_points3 *corner_points, diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c index bcb791d74189..f57f3ba68a02 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.c @@ -516,6 +516,8 @@ void dcn31_link_encoder_construct_minimal( struct dc_context *ctx, const struct encoder_feature_support *enc_features, const struct dcn10_link_enc_registers *link_regs, + const struct dcn10_link_enc_shift *link_shift, + const struct dcn10_link_enc_mask *link_mask, enum engine_id eng_id) { struct dcn10_link_encoder *enc10 = &enc20->enc10; @@ -529,6 +531,8 @@ void dcn31_link_encoder_construct_minimal( enc10->base.features = *enc_features; enc10->base.transmitter = TRANSMITTER_UNKNOWN; enc10->link_regs = link_regs; + enc10->link_shift = link_shift; + enc10->link_mask = link_mask; enc10->base.output_signals = SIGNAL_TYPE_DISPLAY_PORT | diff --git a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h index 3cf587527991..88ab9684e207 100644 --- a/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/dio/dcn31/dcn31_dio_link_encoder.h @@ -246,6 +246,8 @@ void dcn31_link_encoder_construct_minimal( struct dc_context *ctx, const struct encoder_feature_support *enc_features, const struct dcn10_link_enc_registers *link_regs, + const struct dcn10_link_enc_shift *link_shift, + const struct dcn10_link_enc_mask *link_mask, enum engine_id eng_id); void dcn31_link_encoder_set_dio_phy_mux( diff --git a/drivers/gpu/drm/amd/display/dc/dm_services.h b/drivers/gpu/drm/amd/display/dc/dm_services.h index 8b062b011fc6..2cf4bcb03cb0 100644 --- a/drivers/gpu/drm/amd/display/dc/dm_services.h +++ b/drivers/gpu/drm/amd/display/dc/dm_services.h @@ -127,10 +127,6 @@ uint32_t generic_reg_update_ex(const struct dc_context *ctx, struct dc_dmub_srv *dc_dmub_srv_create(struct dc *dc, struct dmub_srv *dmub); void dc_dmub_srv_destroy(struct dc_dmub_srv **dmub_srv); -void reg_sequence_start_gather(const struct dc_context *ctx); -void reg_sequence_start_execute(const struct dc_context *ctx); -void reg_sequence_wait_done(const struct dc_context *ctx); - #define FD(reg_field) reg_field ## __SHIFT, \ reg_field ## _MASK diff --git a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c index dcca23d53261..2ad4a2635683 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c @@ -1237,7 +1237,7 @@ bool dcn_validate_bandwidth( if (pipe->plane_state) { struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; - pipe->plane_state->update_flags.bits.full_update = 1; + pipe->plane_state->update_bits.full_update = 1; if (v->dpp_per_plane[input_idx] == 2 || ((pipe->stream->view_format == diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c index bd14ebea1111..8064c4b3fd25 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c @@ -5337,7 +5337,7 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l for (j = 0; j <= 1; ++j) { double VMDataOnlyReturnBWPerState; double HostVMInefficiencyFactor = 1; - int NextPrefetchModeState = MinPrefetchMode; + unsigned int NextPrefetchModeState = MinPrefetchMode; bool UnboundedRequestEnabledThisState = false; unsigned int CompressedBufferSizeInkByteThisState = 0; double dummy; diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c index 2ea5cf37f273..bf2dde26b98b 100644 --- a/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c +++ b/drivers/gpu/drm/amd/display/dc/dml/dcn314/display_mode_vba_314.c @@ -5421,7 +5421,7 @@ void dml314_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_ for (j = 0; j <= 1; ++j) { double VMDataOnlyReturnBWPerState; double HostVMInefficiencyFactor = 1; - int NextPrefetchModeState = MinPrefetchMode; + unsigned int NextPrefetchModeState = MinPrefetchMode; bool UnboundedRequestEnabledThisState = false; unsigned int CompressedBufferSizeInkByteThisState = 0; double dummy; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c index de40d7bae252..11fc0b1cd152 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/dml21_wrapper_fpu.c @@ -118,16 +118,16 @@ static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_sta context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz; if (in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values > 1) { context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = - in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values] * 1000; + in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values - 1]; } else { - context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0] * 1000; + context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0]; } if (in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values > 1) { context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = - in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values] * 1000; + in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values - 1]; } else { - context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0] * 1000; + context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0]; } /* get global mall allocation */ diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h index ce4025591b87..60ef56419846 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/bounding_boxes/dcn42b_soc_bb.h @@ -75,7 +75,7 @@ static const struct dml2_soc_bb dml2_socbb_dcn42b = { .clk_values_khz = {2}, }, .uclk = { - .clk_values_khz = {400000}, + .clk_values_khz = {2400000}, .num_clk_values = 1, }, .fclk = { @@ -224,4 +224,42 @@ static const struct dml2_soc_bb dml2_socbb_dcn42b = { .max_fclk_for_uclk_dpm_khz = 2200 * 1000, }; +static const struct dml2_ip_capabilities dml2_dcn42b_max_ip_caps = { + .pipe_count = 4, + .otg_count = 3, + .num_dsc = 3, + .max_num_dp2p0_streams = 3, + .max_num_hdmi_frl_outputs = 0, + .max_num_dp2p0_outputs = 2, + .rob_buffer_size_kbytes = 64, + .config_return_buffer_size_in_kbytes = 1792, + .config_return_buffer_segment_size_in_kbytes = 64, + .meta_fifo_size_in_kentries = 32, + .compressed_buffer_segment_size_in_kbytes = 64, + .cursor_buffer_size = 24, + .max_flip_time_us = 110, + .max_flip_time_lines = 50, + .hostvm_mode = 0, + .subvp_drr_scheduling_margin_us = 100, + .subvp_prefetch_end_to_mall_start_us = 15, + .subvp_fw_processing_delay = 15, + .max_vactive_det_fill_delay_us = 400, + + .fams2 = { + .max_allow_delay_us = 100 * 1000, + .scheduling_delay_us = 550, + .vertical_interrupt_ack_delay_us = 40, + .allow_programming_delay_us = 18, + .min_allow_width_us = 20, + .subvp_df_throttle_delay_us = 100, + .subvp_programming_delay_us = 200, + .subvp_prefetch_to_mall_delay_us = 18, + .drr_programming_delay_us = 35, + + .lock_timeout_us = 5000, + .recovery_timeout_us = 5000, + .flip_programming_delay_us = 300, + }, +}; + #endif diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h index 6152155d6073..672b96a3da74 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/inc/dml_top_soc_parameter_types.h @@ -71,8 +71,21 @@ enum dml2_qos_param_type { dml2_qos_param_type_dcn4x }; +//Indicies mapped to DPM level +// Unpopulated indicies should fallback to the global derate value. +struct dml2_soc_derate_values_per_dpm { + unsigned int dram_derate_percent_pixel[DML_MAX_CLK_TABLE_SIZE]; + unsigned int fclk_derate_percent[DML_MAX_CLK_TABLE_SIZE]; + unsigned int dcfclk_derate_percent[DML_MAX_CLK_TABLE_SIZE]; +}; + +struct dml2_soc_derates_per_dpm { + struct dml2_soc_derate_values_per_dpm system_active_derates_per_dpm; +}; + struct dml2_soc_qos_parameters { struct dml2_soc_derates derate_table; + struct dml2_soc_derates_per_dpm derate_table_per_dpm; struct { unsigned int base_latency_us; unsigned int scaling_factor_us; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c index f338e733318e..51a66e1be7a1 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_dcn4_calcs.c @@ -2701,7 +2701,8 @@ static double dml_get_return_bandwidth_available( bool is_hvm_only, double dcfclk_mhz, double fclk_mhz, - double dram_bw_mbps) + double dram_bw_mbps, + unsigned int uclk_dpm_level) { double return_bw_mbps = 0.; double ideal_sdp_bandwidth = (double)soc->return_bus_width_bytes * dcfclk_mhz; @@ -2722,9 +2723,16 @@ static double dml_get_return_bandwidth_available( derate_fabric_factor = soc->qos_parameters.derate_table.dcn_mall_prefetch_average.fclk_derate_percent / 100.0; derate_dram_factor = soc->qos_parameters.derate_table.dcn_mall_prefetch_average.dram_derate_percent_pixel / 100.0; } else { // just assume sys_active - derate_sdp_factor = soc->qos_parameters.derate_table.system_active_average.dcfclk_derate_percent / 100.0; - derate_fabric_factor = soc->qos_parameters.derate_table.system_active_average.fclk_derate_percent / 100.0; - derate_dram_factor = soc->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100.0; + // use per dpm derates if the values are populated. Otherwise use global derates + derate_sdp_factor = soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dcfclk_derate_percent[uclk_dpm_level] != 0 ? + soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dcfclk_derate_percent[uclk_dpm_level] / 100.0 : + soc->qos_parameters.derate_table.system_active_average.dcfclk_derate_percent / 100.0; + derate_fabric_factor = soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.fclk_derate_percent[uclk_dpm_level] != 0 ? + soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.fclk_derate_percent[uclk_dpm_level] / 100.0 : + soc->qos_parameters.derate_table.system_active_average.fclk_derate_percent / 100.0; + derate_dram_factor = soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dram_derate_percent_pixel[uclk_dpm_level] != 0 ? + soc->qos_parameters.derate_table_per_dpm.system_active_derates_per_dpm.dram_derate_percent_pixel[uclk_dpm_level] / 100.0 : + soc->qos_parameters.derate_table.system_active_average.dram_derate_percent_pixel / 100.0; } } else { // urgent bw if (state_type == dml2_core_internal_soc_state_svp_prefetch) { @@ -2778,6 +2786,7 @@ static double dml_get_return_bandwidth_available( DML_LOG_VERBOSE("DML::%s: derate_fabric_bandwidth = %f (derate %f)\n", __func__, derate_fabric_bandwidth, derate_fabric_factor); DML_LOG_VERBOSE("DML::%s: derate_dram_bandwidth = %f (derate %f)\n", __func__, derate_dram_bandwidth, derate_dram_factor); DML_LOG_VERBOSE("DML::%s: return_bw_mbps = %f\n", __func__, return_bw_mbps); + DML_LOG_VERBOSE("DML::%s: uclk_dpm_level = %u\n", __func__, uclk_dpm_level); return return_bw_mbps; } @@ -2793,7 +2802,8 @@ static noinline_for_stack void calculate_bandwidth_available( bool HostVMEnable, double dcfclk_mhz, double fclk_mhz, - double dram_bw_mbps) + double dram_bw_mbps, + unsigned int uclk_dpm_level) { unsigned int n, m; @@ -2812,9 +2822,10 @@ static noinline_for_stack void calculate_bandwidth_available( 0, // hvm_only dcfclk_mhz, fclk_mhz, - dram_bw_mbps); + dram_bw_mbps, + uclk_dpm_level); - urg_bandwidth_available[m][n] = dml_get_return_bandwidth_available(soc, m, n, 0, HostVMEnable, 0, dcfclk_mhz, fclk_mhz, dram_bw_mbps); + urg_bandwidth_available[m][n] = dml_get_return_bandwidth_available(soc, m, n, 0, HostVMEnable, 0, dcfclk_mhz, fclk_mhz, dram_bw_mbps, uclk_dpm_level); #ifdef __DML_VBA_DEBUG__ @@ -2824,8 +2835,8 @@ static noinline_for_stack void calculate_bandwidth_available( // urg_bandwidth_available_vm_only is indexed by soc_state if (n == dml2_core_internal_bw_dram) { - urg_bandwidth_available_vm_only[m] = dml_get_return_bandwidth_available(soc, m, n, 0, HostVMEnable, 1, dcfclk_mhz, fclk_mhz, dram_bw_mbps); - urg_bandwidth_available_pixel_and_vm[m] = dml_get_return_bandwidth_available(soc, m, n, 0, HostVMEnable, 0, dcfclk_mhz, fclk_mhz, dram_bw_mbps); + urg_bandwidth_available_vm_only[m] = dml_get_return_bandwidth_available(soc, m, n, 0, HostVMEnable, 1, dcfclk_mhz, fclk_mhz, dram_bw_mbps, uclk_dpm_level); + urg_bandwidth_available_pixel_and_vm[m] = dml_get_return_bandwidth_available(soc, m, n, 0, HostVMEnable, 0, dcfclk_mhz, fclk_mhz, dram_bw_mbps, uclk_dpm_level); } } @@ -9483,7 +9494,8 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out display_cfg->hostvm_enable, mode_lib->ms.DCFCLK, mode_lib->ms.FabricClock, - mode_lib->ms.dram_bw_mbps); + mode_lib->ms.dram_bw_mbps, + mode_lib->ms.active_min_uclk_dpm_index); calculate_bandwidth_available( mode_lib->ms.support.avg_bandwidth_available_min, @@ -9498,10 +9510,12 @@ static bool dml_core_mode_support(struct dml2_core_calcs_mode_support_ex *in_out mode_lib->ms.MaxDCFCLK, mode_lib->ms.MaxFabricClock, #ifdef DML_MODE_SUPPORT_USE_DPM_DRAM_BW - mode_lib->ms.dram_bw_mbps); + mode_lib->ms.dram_bw_mbps, #else - mode_lib->ms.max_dram_bw_mbps); + mode_lib->ms.max_dram_bw_mbps, #endif + mode_lib->ms.active_min_uclk_dpm_index); + // Average BW support check calculate_avg_bandwidth_required( @@ -10958,7 +10972,8 @@ static bool dml_core_mode_programming(struct dml2_core_calcs_mode_programming_ex display_cfg->hostvm_enable, mode_lib->mp.Dcfclk, mode_lib->mp.FabricClock, - mode_lib->mp.dram_bw_mbps); + mode_lib->mp.dram_bw_mbps, + mode_lib->mp.active_min_uclk_dpm_index); calculate_hostvm_inefficiency_factor( diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.c b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.c index 67e307fa4310..9f1222f5a835 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.c +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_factory.c @@ -15,8 +15,6 @@ bool dml2_core_create(enum dml2_project_id project_id, struct dml2_core_instance memset(out, 0, sizeof(struct dml2_core_instance)); - out->project_id = project_id; - switch (project_id) { case dml2_project_dcn4x_stage1: result = false; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h index 11e295253f72..e9f970794488 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/dml2_core/dml2_core_shared_types.h @@ -2329,7 +2329,6 @@ struct dml2_core_calcs_mode_support_ex { const struct dml2_display_cfg *in_display_cfg; const struct dml2_mcg_min_clock_table *min_clk_table; int min_clk_index; - enum dml2_project_id project_id; //unsigned int in_state_index; struct dml2_core_internal_mode_support_info *out_evaluation_info; }; @@ -2342,7 +2341,6 @@ struct dml2_core_calcs_mode_programming_ex { const struct dml2_mcg_min_clock_table *min_clk_table; const struct core_display_cfg_support_info *cfg_support_info; int min_clk_index; - enum dml2_project_id project_id; struct dml2_display_cfg_programming *programming; }; diff --git a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h index d328d92240b4..3ae817ea2aad 100644 --- a/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h +++ b/drivers/gpu/drm/amd/display/dc/dml2_0/dml21/src/inc/dml2_internal_shared_types.h @@ -489,7 +489,6 @@ struct dml2_core_scratch { }; struct dml2_core_instance { - enum dml2_project_id project_id; struct dml2_mcg_min_clock_table *minimum_clock_table; struct dml2_core_internal_state_inputs inputs; struct dml2_core_internal_state_intermediates intermediates; diff --git a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c index 53b21adc6267..9788628cf0ad 100644 --- a/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c +++ b/drivers/gpu/drm/amd/display/dc/dpp/dcn10/dcn10_dpp_cm.c @@ -397,8 +397,6 @@ void dpp1_cm_program_regamma_lut(struct dpp *dpp_base, uint32_t i; struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); - REG_SEQ_START(); - for (i = 0 ; i < num; i++) { REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].red_reg); REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].green_reg); @@ -408,9 +406,6 @@ void dpp1_cm_program_regamma_lut(struct dpp *dpp_base, REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_green_reg); REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_blue_reg); } - - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); } void dpp1_cm_configure_regamma_lut( diff --git a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h index 95f9318a54ef..c23dc1bb29bf 100644 --- a/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h +++ b/drivers/gpu/drm/amd/display/dc/dwb/dcn30/dcn30_cm_common.h @@ -63,6 +63,10 @@ bool cm3_helper_translate_curve_to_hw_format(struct dc_context *ctx, const struct dc_transfer_func *output_tf, struct pwl_params *lut_params, bool fixpoint); +bool cm3_helper_translate_curve_to_degamma_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params); + bool cm3_helper_convert_to_custom_float( struct pwl_result_data *rgb_resulted, struct curve_points3 *corner_points, diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c b/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c index fabb9da504be..19d148a85f12 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c @@ -35,7 +35,10 @@ #include "dce/dce_8_0_d.h" #include "dce/dce_8_0_sh_mask.h" -#include "smu/smu_7_0_1_d.h" + +#ifndef mmGPIOPAD_A +#define mmGPIOPAD_A 0x0183 +#endif /* * @brief diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c index fecc8688048d..000f603def58 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c @@ -58,146 +58,180 @@ /* macros to expend register list macro defined in HW object header file * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* GENERIC */ + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_A), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_B), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_C), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_D), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_E), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_F), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_G), + /* HPD */ + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK, + GPIO_ID_HPD, GPIO_HPD_1), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK, + GPIO_ID_HPD, GPIO_HPD_2), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK, + GPIO_ID_HPD, GPIO_HPD_3), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK, + GPIO_ID_HPD, GPIO_HPD_4), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK, + GPIO_ID_HPD, GPIO_HPD_5), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK, + GPIO_ID_HPD, GPIO_HPD_6), + /* SYNCA */ + GPIO_MASK_ENTRY(DC_GPIO_SYNCA_A, + DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK, + GPIO_ID_SYNC, GPIO_SYNC_HSYNC_A), + GPIO_MASK_ENTRY(DC_GPIO_SYNCA_A, + DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK, + GPIO_ID_SYNC, GPIO_SYNC_VSYNC_A), + /* GSL */ + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B), +}; + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDC5_A), GPIO_DDC_LINE_DDC5 }, + { REG(DC_GPIO_DDC6_A), GPIO_DDC_LINE_DDC6 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, + { REG(DC_GPIO_I2CPAD_A), GPIO_DDC_LINE_I2C_PAD }, +}; + +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC6, + DC_GPIO_DDC6_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_I2C_PAD, + DC_GPIO_I2CPAD_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC6, + DC_GPIO_DDC6_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_I2C_PAD, + DC_GPIO_I2CPAD_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + /* GENERIC */ + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_A, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_B, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_C, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_D, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_E, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_F, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_G, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK), + /* HPD */ + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_1, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_2, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_3, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_4, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_5, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_6, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK), + /* SYNCA */ + GPIO_PIN_ENTRY(GPIO_ID_SYNC, GPIO_SYNC_HSYNC_A, + DC_GPIO_SYNCA_A, DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_SYNC, GPIO_SYNC_VSYNC_A, + DC_GPIO_SYNCA_A, DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK), + /* GSL */ + GPIO_PIN_ENTRY(GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK, + DC_GPIO_GENLK_A, DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC, + DC_GPIO_GENLK_A, DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A, + DC_GPIO_GENLK_A, DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B, + DC_GPIO_GENLK_A, DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK), +}; + static bool offset_to_id( uint32_t offset, uint32_t mask, enum gpio_id *id, uint32_t *en) { - switch (offset) { - /* GENERIC */ - case REG(DC_GPIO_GENERIC_A): - *id = GPIO_ID_GENERIC; - switch (mask) { - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: - *en = GPIO_GENERIC_A; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: - *en = GPIO_GENERIC_B; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: - *en = GPIO_GENERIC_C; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: - *en = GPIO_GENERIC_D; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: - *en = GPIO_GENERIC_E; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: - *en = GPIO_GENERIC_F; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: - *en = GPIO_GENERIC_G; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* HPD */ - case REG(DC_GPIO_HPD_A): - *id = GPIO_ID_HPD; - switch (mask) { - case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: - *en = GPIO_HPD_1; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: - *en = GPIO_HPD_2; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: - *en = GPIO_HPD_3; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: - *en = GPIO_HPD_4; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: - *en = GPIO_HPD_5; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: - *en = GPIO_HPD_6; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* SYNCA */ - case REG(DC_GPIO_SYNCA_A): - *id = GPIO_ID_SYNC; - switch (mask) { - case DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK: - *en = GPIO_SYNC_HSYNC_A; - return true; - case DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK: - *en = GPIO_SYNC_VSYNC_A; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* REG(DC_GPIO_GENLK_MASK */ - case REG(DC_GPIO_GENLK_A): - *id = GPIO_ID_GSL; - switch (mask) { - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: - *en = GPIO_GSL_GENLOCK_CLOCK; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: - *en = GPIO_GSL_GENLOCK_VSYNC; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: - *en = GPIO_GSL_SWAPLOCK_A; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: - *en = GPIO_GSL_SWAPLOCK_B; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; + + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDC5_A): - *en = GPIO_DDC_LINE_DDC5; - return true; - case REG(DC_GPIO_DDC6_A): - *en = GPIO_DDC_LINE_DDC6; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; - return true; - /* GPIO_I2CPAD */ - case REG(DC_GPIO_I2CPAD_A): - *en = GPIO_DDC_LINE_I2C_PAD; - return true; - /* Not implemented */ - case REG(DC_GPIO_PWRSEQ_A): - case REG(DC_GPIO_PAD_STRENGTH_1): - case REG(DC_GPIO_PAD_STRENGTH_2): - case REG(DC_GPIO_DEBUG): - return false; - /* UNEXPECTED */ - default: - ASSERT_CRITICAL(false); - return false; - } + + ASSERT_CRITICAL(false); + return false; } static bool id_to_offset( @@ -205,186 +239,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC6: - info->offset = REG(DC_GPIO_DDC6_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - info->offset = REG(DC_GPIO_I2CPAD_A); - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC6: - info->offset = REG(DC_GPIO_DDC6_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - info->offset = REG(DC_GPIO_I2CPAD_A); - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GENERIC: - info->offset = REG(DC_GPIO_GENERIC_A); - switch (en) { - case GPIO_GENERIC_A: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; - break; - case GPIO_GENERIC_B: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; - break; - case GPIO_GENERIC_C: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; - break; - case GPIO_GENERIC_D: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; - break; - case GPIO_GENERIC_E: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; - break; - case GPIO_GENERIC_F: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; - break; - case GPIO_GENERIC_G: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_HPD: - info->offset = REG(DC_GPIO_HPD_A); - switch (en) { - case GPIO_HPD_1: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; - break; - case GPIO_HPD_2: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; - break; - case GPIO_HPD_3: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; - break; - case GPIO_HPD_4: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; - break; - case GPIO_HPD_5: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; - break; - case GPIO_HPD_6: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - switch (en) { - case GPIO_SYNC_HSYNC_A: - info->offset = REG(DC_GPIO_SYNCA_A); - info->mask = DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK; - break; - case GPIO_SYNC_VSYNC_A: - info->offset = REG(DC_GPIO_SYNCA_A); - info->mask = DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK; - break; - case GPIO_SYNC_HSYNC_B: - case GPIO_SYNC_VSYNC_B: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GSL: - switch (en) { - case GPIO_GSL_GENLOCK_CLOCK: - info->offset = REG(DC_GPIO_GENLK_A); - info->mask = DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK; - break; - case GPIO_GSL_GENLOCK_VSYNC: - info->offset = REG(DC_GPIO_GENLK_A); - info->mask = - DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK; - break; - case GPIO_GSL_SWAPLOCK_A: - info->offset = REG(DC_GPIO_GENLK_A); - info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK; - break; - case GPIO_GSL_SWAPLOCK_B: - info->offset = REG(DC_GPIO_GENLK_A); - info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } /* function table */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c index 3005ee7751a0..a21df8668266 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn20/hw_translate_dcn20.c @@ -62,131 +62,161 @@ * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* GENERIC */ + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_A), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_B), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_C), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_D), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_E), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_F), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_G), + /* HPD */ + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK, + GPIO_ID_HPD, GPIO_HPD_1), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK, + GPIO_ID_HPD, GPIO_HPD_2), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK, + GPIO_ID_HPD, GPIO_HPD_3), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK, + GPIO_ID_HPD, GPIO_HPD_4), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK, + GPIO_ID_HPD, GPIO_HPD_5), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK, + GPIO_ID_HPD, GPIO_HPD_6), + /* GSL */ + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B), +}; + + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDC5_A), GPIO_DDC_LINE_DDC5 }, + { REG(DC_GPIO_DDC6_A), GPIO_DDC_LINE_DDC6 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, +}; + + +/* + * GSL is intentionally omitted here. + * id_to_offset() for GSL is not implemented on this ASIC. + */ +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC6, + DC_GPIO_DDC6_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC6, + DC_GPIO_DDC6_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + /* GENERIC */ + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_A, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_B, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_C, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_D, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_E, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_F, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_G, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK), + /* HPD */ + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_1, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_2, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_3, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_4, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_5, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_6, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK), +}; + + static bool offset_to_id( uint32_t offset, uint32_t mask, enum gpio_id *id, uint32_t *en) { - switch (offset) { - /* GENERIC */ - case REG(DC_GPIO_GENERIC_A): - *id = GPIO_ID_GENERIC; - switch (mask) { - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: - *en = GPIO_GENERIC_A; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: - *en = GPIO_GENERIC_B; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: - *en = GPIO_GENERIC_C; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: - *en = GPIO_GENERIC_D; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: - *en = GPIO_GENERIC_E; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: - *en = GPIO_GENERIC_F; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: - *en = GPIO_GENERIC_G; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* HPD */ - case REG(DC_GPIO_HPD_A): - *id = GPIO_ID_HPD; - switch (mask) { - case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: - *en = GPIO_HPD_1; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: - *en = GPIO_HPD_2; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: - *en = GPIO_HPD_3; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: - *en = GPIO_HPD_4; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: - *en = GPIO_HPD_5; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: - *en = GPIO_HPD_6; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* REG(DC_GPIO_GENLK_MASK */ - case REG(DC_GPIO_GENLK_A): - *id = GPIO_ID_GSL; - switch (mask) { - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: - *en = GPIO_GSL_GENLOCK_CLOCK; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: - *en = GPIO_GSL_GENLOCK_VSYNC; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: - *en = GPIO_GSL_SWAPLOCK_A; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: - *en = GPIO_GSL_SWAPLOCK_B; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method - */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; - return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; - return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDC5_A): - *en = GPIO_DDC_LINE_DDC5; - return true; - case REG(DC_GPIO_DDC6_A): - *en = GPIO_DDC_LINE_DDC6; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; -/* - * case REG(DC_GPIO_I2CPAD_A): not exit - * case REG(DC_GPIO_PWRSEQ_A): - * case REG(DC_GPIO_PAD_STRENGTH_1): - * case REG(DC_GPIO_PAD_STRENGTH_2): - * case REG(DC_GPIO_DEBUG): - */ - /* UNEXPECTED */ - default: -/* case REG(DC_GPIO_SYNCA_A): not exist */ - ASSERT_CRITICAL(false); - return false; - } + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) + return true; + + ASSERT_CRITICAL(false); + return false; } static bool id_to_offset( @@ -194,170 +224,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC6: - info->offset = REG(DC_GPIO_DDC6_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC6: - info->offset = REG(DC_GPIO_DDC6_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GENERIC: - info->offset = REG(DC_GPIO_GENERIC_A); - switch (en) { - case GPIO_GENERIC_A: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; - break; - case GPIO_GENERIC_B: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; - break; - case GPIO_GENERIC_C: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; - break; - case GPIO_GENERIC_D: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; - break; - case GPIO_GENERIC_E: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; - break; - case GPIO_GENERIC_F: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; - break; - case GPIO_GENERIC_G: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_HPD: - info->offset = REG(DC_GPIO_HPD_A); - switch (en) { - case GPIO_HPD_1: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; - break; - case GPIO_HPD_2: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; - break; - case GPIO_HPD_3: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; - break; - case GPIO_HPD_4: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; - break; - case GPIO_HPD_5: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; - break; - case GPIO_HPD_6: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GSL: - switch (en) { - case GPIO_GSL_GENLOCK_CLOCK: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_GENLOCK_VSYNC: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_A: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_B: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } /* function table */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c index e3b11b3c1daa..18bd4d4e32d0 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn21/hw_translate_dcn21.c @@ -60,6 +60,135 @@ /* macros to expend register list macro defined in HW object header file * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* GENERIC */ + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_A), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_B), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_C), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_D), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_E), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_F), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_G), + /* HPD */ + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK, + GPIO_ID_HPD, GPIO_HPD_1), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK, + GPIO_ID_HPD, GPIO_HPD_2), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK, + GPIO_ID_HPD, GPIO_HPD_3), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK, + GPIO_ID_HPD, GPIO_HPD_4), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK, + GPIO_ID_HPD, GPIO_HPD_5), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK, + GPIO_ID_HPD, GPIO_HPD_6), + /* GSL */ + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B), +}; + + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDC5_A), GPIO_DDC_LINE_DDC5 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, +}; + + +/* + * GSL is intentionally omitted here. + * id_to_offset() for GSL is not implemented on this ASIC. + */ +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK), + /* GENERIC */ + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_A, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_B, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_C, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_D, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_E, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_F, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_G, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK), + /* HPD */ + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_1, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_2, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_3, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_4, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_5, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_6, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK), +}; + static bool offset_to_id( uint32_t offset, @@ -67,122 +196,20 @@ static bool offset_to_id( enum gpio_id *id, uint32_t *en) { - switch (offset) { - /* GENERIC */ - case REG(DC_GPIO_GENERIC_A): - *id = GPIO_ID_GENERIC; - switch (mask) { - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: - *en = GPIO_GENERIC_A; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: - *en = GPIO_GENERIC_B; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: - *en = GPIO_GENERIC_C; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: - *en = GPIO_GENERIC_D; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: - *en = GPIO_GENERIC_E; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: - *en = GPIO_GENERIC_F; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: - *en = GPIO_GENERIC_G; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* HPD */ - case REG(DC_GPIO_HPD_A): - *id = GPIO_ID_HPD; - switch (mask) { - case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: - *en = GPIO_HPD_1; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: - *en = GPIO_HPD_2; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: - *en = GPIO_HPD_3; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: - *en = GPIO_HPD_4; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: - *en = GPIO_HPD_5; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: - *en = GPIO_HPD_6; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* REG(DC_GPIO_GENLK_MASK */ - case REG(DC_GPIO_GENLK_A): - *id = GPIO_ID_GSL; - switch (mask) { - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: - *en = GPIO_GSL_GENLOCK_CLOCK; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: - *en = GPIO_GSL_GENLOCK_VSYNC; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: - *en = GPIO_GSL_SWAPLOCK_A; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: - *en = GPIO_GSL_SWAPLOCK_B; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method - */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; - return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; - return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDC5_A): - *en = GPIO_DDC_LINE_DDC5; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; -/* - * case REG(DC_GPIO_I2CPAD_A): not exit - * case REG(DC_GPIO_PWRSEQ_A): - * case REG(DC_GPIO_PAD_STRENGTH_1): - * case REG(DC_GPIO_PAD_STRENGTH_2): - * case REG(DC_GPIO_DEBUG): - */ - /* UNEXPECTED */ - default: -/* case REG(DC_GPIO_SYNCA_A): not exist */ - ASSERT_CRITICAL(false); - return false; - } + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) + return true; + + ASSERT_CRITICAL(false); + return false; } static bool id_to_offset( @@ -190,164 +217,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GENERIC: - info->offset = REG(DC_GPIO_GENERIC_A); - switch (en) { - case GPIO_GENERIC_A: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; - break; - case GPIO_GENERIC_B: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; - break; - case GPIO_GENERIC_C: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; - break; - case GPIO_GENERIC_D: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; - break; - case GPIO_GENERIC_E: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; - break; - case GPIO_GENERIC_F: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; - break; - case GPIO_GENERIC_G: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_HPD: - info->offset = REG(DC_GPIO_HPD_A); - switch (en) { - case GPIO_HPD_1: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; - break; - case GPIO_HPD_2: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; - break; - case GPIO_HPD_3: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; - break; - case GPIO_HPD_4: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; - break; - case GPIO_HPD_5: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; - break; - case GPIO_HPD_6: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GSL: - switch (en) { - case GPIO_GSL_GENLOCK_CLOCK: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_GENLOCK_VSYNC: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_A: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_B: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } /* function table */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c index 49d6250037a9..c4225231f725 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c @@ -67,131 +67,161 @@ * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* GENERIC */ + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_A), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_B), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_C), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_D), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_E), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_F), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_G), + /* HPD */ + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK, + GPIO_ID_HPD, GPIO_HPD_1), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK, + GPIO_ID_HPD, GPIO_HPD_2), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK, + GPIO_ID_HPD, GPIO_HPD_3), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK, + GPIO_ID_HPD, GPIO_HPD_4), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK, + GPIO_ID_HPD, GPIO_HPD_5), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK, + GPIO_ID_HPD, GPIO_HPD_6), + /* GSL */ + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B), +}; + + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDC5_A), GPIO_DDC_LINE_DDC5 }, + { REG(DC_GPIO_DDC6_A), GPIO_DDC_LINE_DDC6 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, +}; + + +/* + * GSL is intentionally omitted here. + * id_to_offset() for GSL is not implemented on this ASIC. + */ +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC6, + DC_GPIO_DDC6_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC6, + DC_GPIO_DDC6_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK), + /* GENERIC */ + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_A, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_B, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_C, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_D, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_E, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_F, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_G, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK), + /* HPD */ + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_1, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_2, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_3, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_4, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_5, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_6, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK), +}; + + static bool offset_to_id( uint32_t offset, uint32_t mask, enum gpio_id *id, uint32_t *en) { - switch (offset) { - /* GENERIC */ - case REG(DC_GPIO_GENERIC_A): - *id = GPIO_ID_GENERIC; - switch (mask) { - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: - *en = GPIO_GENERIC_A; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: - *en = GPIO_GENERIC_B; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: - *en = GPIO_GENERIC_C; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: - *en = GPIO_GENERIC_D; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: - *en = GPIO_GENERIC_E; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: - *en = GPIO_GENERIC_F; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: - *en = GPIO_GENERIC_G; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* HPD */ - case REG(DC_GPIO_HPD_A): - *id = GPIO_ID_HPD; - switch (mask) { - case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: - *en = GPIO_HPD_1; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: - *en = GPIO_HPD_2; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: - *en = GPIO_HPD_3; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: - *en = GPIO_HPD_4; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: - *en = GPIO_HPD_5; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: - *en = GPIO_HPD_6; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* REG(DC_GPIO_GENLK_MASK */ - case REG(DC_GPIO_GENLK_A): - *id = GPIO_ID_GSL; - switch (mask) { - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: - *en = GPIO_GSL_GENLOCK_CLOCK; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: - *en = GPIO_GSL_GENLOCK_VSYNC; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: - *en = GPIO_GSL_SWAPLOCK_A; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: - *en = GPIO_GSL_SWAPLOCK_B; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method - */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; - return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; - return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDC5_A): - *en = GPIO_DDC_LINE_DDC5; - return true; - case REG(DC_GPIO_DDC6_A): - *en = GPIO_DDC_LINE_DDC6; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; -/* - * case REG(DC_GPIO_I2CPAD_A): not exit - * case REG(DC_GPIO_PWRSEQ_A): - * case REG(DC_GPIO_PAD_STRENGTH_1): - * case REG(DC_GPIO_PAD_STRENGTH_2): - * case REG(DC_GPIO_DEBUG): - */ - /* UNEXPECTED */ - default: -/* case REG(DC_GPIO_SYNCA_A): not exist */ - ASSERT_CRITICAL(false); - return false; - } + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) + return true; + + ASSERT_CRITICAL(false); + return false; } static bool id_to_offset( @@ -199,170 +229,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC6: - info->offset = REG(DC_GPIO_DDC6_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC6: - info->offset = REG(DC_GPIO_DDC6_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GENERIC: - info->offset = REG(DC_GPIO_GENERIC_A); - switch (en) { - case GPIO_GENERIC_A: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; - break; - case GPIO_GENERIC_B: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; - break; - case GPIO_GENERIC_C: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; - break; - case GPIO_GENERIC_D: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; - break; - case GPIO_GENERIC_E: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; - break; - case GPIO_GENERIC_F: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; - break; - case GPIO_GENERIC_G: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_HPD: - info->offset = REG(DC_GPIO_HPD_A); - switch (en) { - case GPIO_HPD_1: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; - break; - case GPIO_HPD_2: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; - break; - case GPIO_HPD_3: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; - break; - case GPIO_HPD_4: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; - break; - case GPIO_HPD_5: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; - break; - case GPIO_HPD_6: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GSL: - switch (en) { - case GPIO_GSL_GENLOCK_CLOCK: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_GENLOCK_VSYNC: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_A: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_B: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } /* function table */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c index fbdaba57f718..aa507f7f4ef9 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c @@ -62,128 +62,156 @@ * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* GENERIC */ + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_A), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_B), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_C), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_D), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_E), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_F), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_G), + /* HPD */ + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK, + GPIO_ID_HPD, GPIO_HPD_1), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK, + GPIO_ID_HPD, GPIO_HPD_2), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK, + GPIO_ID_HPD, GPIO_HPD_3), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK, + GPIO_ID_HPD, GPIO_HPD_4), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK, + GPIO_ID_HPD, GPIO_HPD_5), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK, + GPIO_ID_HPD, GPIO_HPD_6), + /* GSL */ + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B), +}; + + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDC5_A), GPIO_DDC_LINE_DDC5 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, +}; + + +/* + * GSL is intentionally omitted here. + * id_to_offset() for GSL is not implemented on this ASIC. + */ +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + /* GENERIC */ + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_A, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_B, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_C, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_D, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_E, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_F, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_G, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK), + /* HPD */ + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_1, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_2, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_3, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_4, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_5, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_6, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK), +}; + + static bool offset_to_id( uint32_t offset, uint32_t mask, enum gpio_id *id, uint32_t *en) { - switch (offset) { - /* GENERIC */ - case REG(DC_GPIO_GENERIC_A): - *id = GPIO_ID_GENERIC; - switch (mask) { - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: - *en = GPIO_GENERIC_A; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: - *en = GPIO_GENERIC_B; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: - *en = GPIO_GENERIC_C; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: - *en = GPIO_GENERIC_D; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: - *en = GPIO_GENERIC_E; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: - *en = GPIO_GENERIC_F; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK: - *en = GPIO_GENERIC_G; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* HPD */ - case REG(DC_GPIO_HPD_A): - *id = GPIO_ID_HPD; - switch (mask) { - case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: - *en = GPIO_HPD_1; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: - *en = GPIO_HPD_2; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: - *en = GPIO_HPD_3; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: - *en = GPIO_HPD_4; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: - *en = GPIO_HPD_5; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK: - *en = GPIO_HPD_6; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* REG(DC_GPIO_GENLK_MASK */ - case REG(DC_GPIO_GENLK_A): - *id = GPIO_ID_GSL; - switch (mask) { - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: - *en = GPIO_GSL_GENLOCK_CLOCK; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: - *en = GPIO_GSL_GENLOCK_VSYNC; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: - *en = GPIO_GSL_SWAPLOCK_A; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: - *en = GPIO_GSL_SWAPLOCK_B; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method - */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; - return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; - return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDC5_A): - *en = GPIO_DDC_LINE_DDC5; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; -/* - * case REG(DC_GPIO_I2CPAD_A): not exit - * case REG(DC_GPIO_PWRSEQ_A): - * case REG(DC_GPIO_PAD_STRENGTH_1): - * case REG(DC_GPIO_PAD_STRENGTH_2): - * case REG(DC_GPIO_DEBUG): - */ - /* UNEXPECTED */ - default: -/* case REG(DC_GPIO_SYNCA_A): not exist */ - ASSERT_CRITICAL(false); - return false; - } + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) + return true; + + ASSERT_CRITICAL(false); + return false; } static bool id_to_offset( @@ -191,164 +219,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GENERIC: - info->offset = REG(DC_GPIO_GENERIC_A); - switch (en) { - case GPIO_GENERIC_A: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; - break; - case GPIO_GENERIC_B: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; - break; - case GPIO_GENERIC_C: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; - break; - case GPIO_GENERIC_D: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; - break; - case GPIO_GENERIC_E: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; - break; - case GPIO_GENERIC_F: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; - break; - case GPIO_GENERIC_G: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_HPD: - info->offset = REG(DC_GPIO_HPD_A); - switch (en) { - case GPIO_HPD_1: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; - break; - case GPIO_HPD_2: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; - break; - case GPIO_HPD_3: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; - break; - case GPIO_HPD_4: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; - break; - case GPIO_HPD_5: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; - break; - case GPIO_HPD_6: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GSL: - switch (en) { - case GPIO_GSL_GENLOCK_CLOCK: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_GENLOCK_VSYNC: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_A: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_B: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } /* function table */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_translate_dcn32.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_translate_dcn32.c index 8493b9981f9e..71067a8da121 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_translate_dcn32.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn32/hw_translate_dcn32.c @@ -60,111 +60,145 @@ * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* GENERIC */ + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_A), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_B), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_C), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_D), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_E), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_F), + /* HPD */ + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK, + GPIO_ID_HPD, GPIO_HPD_1), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK, + GPIO_ID_HPD, GPIO_HPD_2), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK, + GPIO_ID_HPD, GPIO_HPD_3), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK, + GPIO_ID_HPD, GPIO_HPD_4), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK, + GPIO_ID_HPD, GPIO_HPD_5), + /* GSL */ + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B), +}; + + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDC5_A), GPIO_DDC_LINE_DDC5 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, +}; + +/* + * GSL is intentionally omitted here. + * id_to_offset() for GSL is not implemented on this ASIC. + */ +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + /* GENERIC */ + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_A, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_B, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_C, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_D, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_E, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_F, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK), + /* HPD */ + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_1, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_2, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_3, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_4, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_5, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK), +}; + + static bool offset_to_id( uint32_t offset, uint32_t mask, enum gpio_id *id, uint32_t *en) { - switch (offset) { - /* GENERIC */ - case REG(DC_GPIO_GENERIC_A): - *id = GPIO_ID_GENERIC; - switch (mask) { - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: - *en = GPIO_GENERIC_A; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: - *en = GPIO_GENERIC_B; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: - *en = GPIO_GENERIC_C; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: - *en = GPIO_GENERIC_D; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: - *en = GPIO_GENERIC_E; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: - *en = GPIO_GENERIC_F; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* HPD */ - case REG(DC_GPIO_HPD_A): - *id = GPIO_ID_HPD; - switch (mask) { - case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: - *en = GPIO_HPD_1; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: - *en = GPIO_HPD_2; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: - *en = GPIO_HPD_3; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: - *en = GPIO_HPD_4; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: - *en = GPIO_HPD_5; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* REG(DC_GPIO_GENLK_MASK */ - case REG(DC_GPIO_GENLK_A): - *id = GPIO_ID_GSL; - switch (mask) { - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: - *en = GPIO_GSL_GENLOCK_CLOCK; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: - *en = GPIO_GSL_GENLOCK_VSYNC; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: - *en = GPIO_GSL_SWAPLOCK_A; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: - *en = GPIO_GSL_SWAPLOCK_B; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; + + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDC5_A): - *en = GPIO_DDC_LINE_DDC5; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } + + ASSERT_CRITICAL(false); + return false; } static bool id_to_offset( @@ -172,158 +206,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GENERIC: - info->offset = REG(DC_GPIO_GENERIC_A); - switch (en) { - case GPIO_GENERIC_A: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; - break; - case GPIO_GENERIC_B: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; - break; - case GPIO_GENERIC_C: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; - break; - case GPIO_GENERIC_D: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; - break; - case GPIO_GENERIC_E: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; - break; - case GPIO_GENERIC_F: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_HPD: - info->offset = REG(DC_GPIO_HPD_A); - switch (en) { - case GPIO_HPD_1: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; - break; - case GPIO_HPD_2: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; - break; - case GPIO_HPD_3: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; - break; - case GPIO_HPD_4: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; - break; - case GPIO_HPD_5: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GSL: - switch (en) { - case GPIO_GSL_GENLOCK_CLOCK: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_GENLOCK_VSYNC: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_A: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_B: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } /* function table */ diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn401/hw_translate_dcn401.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn401/hw_translate_dcn401.c index ea416f01f888..7aa97f09955c 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn401/hw_translate_dcn401.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn401/hw_translate_dcn401.c @@ -35,119 +35,145 @@ * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* GENERIC */ + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_A), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_B), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_C), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_D), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_E), + GPIO_MASK_ENTRY(DC_GPIO_GENERIC_A, + DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK, + GPIO_ID_GENERIC, GPIO_GENERIC_F), + /* HPD */ + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK, + GPIO_ID_HPD, GPIO_HPD_1), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK, + GPIO_ID_HPD, GPIO_HPD_2), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK, + GPIO_ID_HPD, GPIO_HPD_3), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK, + GPIO_ID_HPD, GPIO_HPD_4), + GPIO_MASK_ENTRY(DC_GPIO_HPD_A, + DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK, + GPIO_ID_HPD, GPIO_HPD_5), + /* GSL */ + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_CLOCK), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK, + GPIO_ID_GSL, GPIO_GSL_GENLOCK_VSYNC), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_A), + GPIO_MASK_ENTRY(DC_GPIO_GENLK_A, + DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK, + GPIO_ID_GSL, GPIO_GSL_SWAPLOCK_B), +}; + + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, +}; + + +/* + * GSL is intentionally omitted here. + * id_to_offset() for GSL is not implemented on this ASIC. + */ +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + /* GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + /* GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + /* GENERIC */ + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_A, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_B, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_C, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_D, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_E, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_GENERIC, GPIO_GENERIC_F, + DC_GPIO_GENERIC_A, DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK), + /* HPD */ + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_1, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_2, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_3, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_4, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_HPD, GPIO_HPD_5, + DC_GPIO_HPD_A, DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK), +}; + + static bool offset_to_id( uint32_t offset, uint32_t mask, enum gpio_id *id, uint32_t *en) { - switch (offset) { - /* GENERIC */ - case REG(DC_GPIO_GENERIC_A): - *id = GPIO_ID_GENERIC; - switch (mask) { - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK: - *en = GPIO_GENERIC_A; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK: - *en = GPIO_GENERIC_B; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK: - *en = GPIO_GENERIC_C; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK: - *en = GPIO_GENERIC_D; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK: - *en = GPIO_GENERIC_E; - return true; - case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK: - *en = GPIO_GENERIC_F; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* HPD */ - case REG(DC_GPIO_HPD_A): - *id = GPIO_ID_HPD; - switch (mask) { - case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK: - *en = GPIO_HPD_1; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK: - *en = GPIO_HPD_2; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK: - *en = GPIO_HPD_3; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK: - *en = GPIO_HPD_4; - return true; - case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK: - *en = GPIO_HPD_5; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* REG(DC_GPIO_GENLK_MASK */ - case REG(DC_GPIO_GENLK_A): - *id = GPIO_ID_GSL; - switch (mask) { - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK: - *en = GPIO_GSL_GENLOCK_CLOCK; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK: - *en = GPIO_GSL_GENLOCK_VSYNC; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK: - *en = GPIO_GSL_SWAPLOCK_A; - return true; - case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK: - *en = GPIO_GSL_SWAPLOCK_B; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } - break; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method - */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; - return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; - return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; -/* - * case REG(DC_GPIO_I2CPAD_A): not exit - * case REG(DC_GPIO_PWRSEQ_A): - * case REG(DC_GPIO_PAD_STRENGTH_1): - * case REG(DC_GPIO_PAD_STRENGTH_2): - * case REG(DC_GPIO_DEBUG): - */ - /* UNEXPECTED */ - default: -/* case REG(DC_GPIO_SYNCA_A): not exist */ - ASSERT_CRITICAL(false); - return false; - } + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) + return true; + + ASSERT_CRITICAL(false); + return false; } @@ -156,158 +182,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; -/* case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; */ - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; -/* case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; */ - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GENERIC: - info->offset = REG(DC_GPIO_GENERIC_A); - switch (en) { - case GPIO_GENERIC_A: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK; - break; - case GPIO_GENERIC_B: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK; - break; - case GPIO_GENERIC_C: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK; - break; - case GPIO_GENERIC_D: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK; - break; - case GPIO_GENERIC_E: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK; - break; - case GPIO_GENERIC_F: - info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_HPD: - info->offset = REG(DC_GPIO_HPD_A); - switch (en) { - case GPIO_HPD_1: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK; - break; - case GPIO_HPD_2: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK; - break; - case GPIO_HPD_3: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK; - break; - case GPIO_HPD_4: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK; - break; - case GPIO_HPD_5: - info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK; - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_GSL: - switch (en) { - case GPIO_GSL_GENLOCK_CLOCK: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_GENLOCK_VSYNC: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_A: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - break; - case GPIO_GSL_SWAPLOCK_B: - /*not implmented*/ - ASSERT_CRITICAL(false); - result = false; - - break; - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c index e7e1d9979876..7b2c4cd42450 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn42/hw_translate_dcn42.c @@ -39,62 +39,76 @@ * end *********************/ +static const struct gpio_id_offset_entry gpio_offsets[] = { + /* HPD */ + GPIO_ENTRY(HPD0_DC_HPD_INT_STATUS, GPIO_ID_HPD, GPIO_HPD_1), + GPIO_ENTRY(HPD1_DC_HPD_INT_STATUS, GPIO_ID_HPD, GPIO_HPD_2), + GPIO_ENTRY(HPD2_DC_HPD_INT_STATUS, GPIO_ID_HPD, GPIO_HPD_3), + GPIO_ENTRY(HPD3_DC_HPD_INT_STATUS, GPIO_ID_HPD, GPIO_HPD_4), + GPIO_ENTRY(HPD4_DC_HPD_INT_STATUS, GPIO_ID_HPD, GPIO_HPD_5), +}; + + +/* DDC */ +static const struct gpio_ddc_offset_entry ddc_offset_map[] = { + { REG(DC_GPIO_DDC1_A), GPIO_DDC_LINE_DDC1 }, + { REG(DC_GPIO_DDC2_A), GPIO_DDC_LINE_DDC2 }, + { REG(DC_GPIO_DDC3_A), GPIO_DDC_LINE_DDC3 }, + { REG(DC_GPIO_DDC4_A), GPIO_DDC_LINE_DDC4 }, + { REG(DC_GPIO_DDC5_A), GPIO_DDC_LINE_DDC5 }, + { REG(DC_GPIO_DDCVGA_A), GPIO_DDC_LINE_DDC_VGA }, +}; + + +static const struct gpio_pin_entry gpio_pins[] = { + /* DDC */ + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_DATA, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC1, + DC_GPIO_DDC1_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC2, + DC_GPIO_DDC2_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC3, + DC_GPIO_DDC3_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC4, + DC_GPIO_DDC4_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC5, + DC_GPIO_DDC5_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), + GPIO_PIN_ENTRY(GPIO_ID_DDC_CLOCK, GPIO_DDC_LINE_DDC_VGA, + DC_GPIO_DDCVGA_A, DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK), +}; + + static bool offset_to_id( uint32_t offset, uint32_t mask, enum gpio_id *id, uint32_t *en) { - (void)mask; - switch (offset) { - /* HPD */ - case REG(HPD0_DC_HPD_INT_STATUS): - *id = GPIO_ID_HPD; - *en = GPIO_HPD_1; + if (dal_hw_translate_gpio_ddc_offset_to_id( + ddc_offset_map, + ARRAY_SIZE(ddc_offset_map), + offset, en)) return true; - case REG(HPD1_DC_HPD_INT_STATUS): - *id = GPIO_ID_HPD; - *en = GPIO_HPD_2; + + if (dal_hw_translate_gpio_offset_to_id( + gpio_offsets, + ARRAY_SIZE(gpio_offsets), + offset, mask, id, en)) return true; - case REG(HPD2_DC_HPD_INT_STATUS): - *id = GPIO_ID_HPD; - *en = GPIO_HPD_3; - return true; - case REG(HPD3_DC_HPD_INT_STATUS): - *id = GPIO_ID_HPD; - *en = GPIO_HPD_4; - return true; - case REG(HPD4_DC_HPD_INT_STATUS): - *id = GPIO_ID_HPD; - *en = GPIO_HPD_5; - return true; - /* DDC */ - /* we don't care about the GPIO_ID for DDC - * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK - * directly in the create method - */ - case REG(DC_GPIO_DDC1_A): - *en = GPIO_DDC_LINE_DDC1; - return true; - case REG(DC_GPIO_DDC2_A): - *en = GPIO_DDC_LINE_DDC2; - return true; - case REG(DC_GPIO_DDC3_A): - *en = GPIO_DDC_LINE_DDC3; - return true; - case REG(DC_GPIO_DDC4_A): - *en = GPIO_DDC_LINE_DDC4; - return true; - case REG(DC_GPIO_DDC5_A): - *en = GPIO_DDC_LINE_DDC5; - return true; - case REG(DC_GPIO_DDCVGA_A): - *en = GPIO_DDC_LINE_DDC_VGA; - return true; - default: - ASSERT_CRITICAL(false); - return false; - } + + ASSERT_CRITICAL(false); + return false; } @@ -103,81 +117,14 @@ static bool id_to_offset( uint32_t en, struct gpio_pin_info *info) { - bool result = true; + if (dal_hw_translate_id_to_offset( + gpio_pins, + ARRAY_SIZE(gpio_pins), + id, en, info)) + return true; - switch (id) { - case GPIO_ID_DDC_DATA: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_DDC_CLOCK: - info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK; - switch (en) { - case GPIO_DDC_LINE_DDC1: - info->offset = REG(DC_GPIO_DDC1_A); - break; - case GPIO_DDC_LINE_DDC2: - info->offset = REG(DC_GPIO_DDC2_A); - break; - case GPIO_DDC_LINE_DDC3: - info->offset = REG(DC_GPIO_DDC3_A); - break; - case GPIO_DDC_LINE_DDC4: - info->offset = REG(DC_GPIO_DDC4_A); - break; - case GPIO_DDC_LINE_DDC5: - info->offset = REG(DC_GPIO_DDC5_A); - break; - case GPIO_DDC_LINE_DDC_VGA: - info->offset = REG(DC_GPIO_DDCVGA_A); - break; - case GPIO_DDC_LINE_I2C_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - break; - case GPIO_ID_SYNC: - case GPIO_ID_VIP_PAD: - default: - ASSERT_CRITICAL(false); - result = false; - } - - if (result) { - info->offset_y = info->offset + 2; - info->offset_en = info->offset + 1; - info->offset_mask = info->offset - 1; - - info->mask_y = info->mask; - info->mask_en = info->mask; - info->mask_mask = info->mask; - } - - return result; + ASSERT_CRITICAL(false); + return false; } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index 64a5e11fce5c..b58af86dee10 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -133,3 +133,89 @@ bool dal_hw_translate_init( return false; } } + +bool dal_hw_translate_gpio_offset_to_id( + const struct gpio_id_offset_entry *table, + uint32_t table_size, + uint32_t offset, + uint32_t mask, + enum gpio_id *id, + uint32_t *en) +{ + uint32_t i; + + for (i = 0; i < table_size; i++) { + const struct gpio_id_offset_entry *entry = &table[i]; + + if (entry->offset != offset) + continue; + + if (entry->check_mask && entry->mask != mask) + continue; + + *id = entry->id; + *en = entry->en; + + return true; + } + + return false; +} + +/* we don't care about the GPIO_ID for DDC + * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK + * directly in the create method + */ +bool dal_hw_translate_gpio_ddc_offset_to_id( + const struct gpio_ddc_offset_entry *table, + uint32_t table_size, + uint32_t offset, + uint32_t *en) +{ + uint32_t i; + + for (i = 0; i < table_size; i++) { + const struct gpio_ddc_offset_entry *entry = &table[i]; + + if (entry->offset != offset) + continue; + + *en = entry->en; + + return true; + } + + return false; +} + +bool dal_hw_translate_id_to_offset( + const struct gpio_pin_entry *table, + uint32_t table_size, + enum gpio_id id, + uint32_t en, + struct gpio_pin_info *info) +{ + uint32_t i; + + for (i = 0; i < table_size; i++) { + const struct gpio_pin_entry *entry = &table[i]; + + if (entry->id != id || entry->en != en) + continue; + + info->offset = entry->offset; + info->mask = entry->mask; + + info->offset_y = info->offset + 2; + info->offset_en = info->offset + 1; + info->offset_mask = info->offset - 1; + + info->mask_y = info->mask; + info->mask_en = info->mask; + info->mask_mask = info->mask; + + return true; + } + + return false; +} diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.h b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.h index 3a7d89ca1605..339e381f8fde 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.h +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.h @@ -47,4 +47,25 @@ bool dal_hw_translate_init( enum dce_version dce_version, enum dce_environment dce_environment); +bool dal_hw_translate_gpio_offset_to_id( + const struct gpio_id_offset_entry *table, + uint32_t table_size, + uint32_t offset, + uint32_t mask, + enum gpio_id *id, + uint32_t *en); + +bool dal_hw_translate_gpio_ddc_offset_to_id( + const struct gpio_ddc_offset_entry *table, + uint32_t table_size, + uint32_t offset, + uint32_t *en); + +bool dal_hw_translate_id_to_offset( + const struct gpio_pin_entry *table, + uint32_t table_size, + enum gpio_id id, + uint32_t en, + struct gpio_pin_info *info); + #endif diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c index 79cb506be5cb..cbcd22789013 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn31/dcn31_hubbub.c @@ -138,10 +138,10 @@ static void dcn31_program_compbuf_size(struct hubbub *hubbub, unsigned int compb if (safe_to_increase || compbuf_size_segments <= hubbub2->compbuf_size_segments) { if (compbuf_size_segments > hubbub2->compbuf_size_segments) { - REG_WAIT(DCHUBBUB_DET0_CTRL, DET0_SIZE_CURRENT, hubbub2->det0_size, 1, 100); - REG_WAIT(DCHUBBUB_DET1_CTRL, DET1_SIZE_CURRENT, hubbub2->det1_size, 1, 100); - REG_WAIT(DCHUBBUB_DET2_CTRL, DET2_SIZE_CURRENT, hubbub2->det2_size, 1, 100); - REG_WAIT(DCHUBBUB_DET3_CTRL, DET3_SIZE_CURRENT, hubbub2->det3_size, 1, 100); + dcn31_wait_for_det_apply(hubbub, 0); + dcn31_wait_for_det_apply(hubbub, 1); + dcn31_wait_for_det_apply(hubbub, 2); + dcn31_wait_for_det_apply(hubbub, 3); } /* Should never be hit, if it is we have an erroneous hw config*/ ASSERT(hubbub2->det0_size + hubbub2->det1_size + hubbub2->det2_size diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c index 82d4e3e0e5e8..5e5a7a74346d 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c @@ -571,7 +571,7 @@ void dcn35_dchvm_init(struct hubbub *hubbub) if (riommu_active) { // Disable gating and memory power requests - REG_UPDATE(DCHVM_MEM_CTRL, HVM_GPUVMRET_PWR_REQ_DIS, 1); + REG_UPDATE_2(DCHVM_MEM_CTRL, HVM_GPUVMRET_PWR_REQ_DIS, 1, HVM_GPUVMRET_FORCE_REQ, 0); REG_UPDATE_4(DCHVM_CLK_CTRL, HVM_DISPCLK_R_GATE_DIS, 1, HVM_DISPCLK_G_GATE_DIS, 1, diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c index 302515128358..9965cf572354 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn401/dcn401_hubp.c @@ -136,7 +136,7 @@ void hubp401_program_3dlut_fl_config( uint32_t mpc_width = {(cfg->width == 17) ? 0 : 1}; uint32_t width = {cfg->width}; - if (cfg->layout == DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR) + if (cfg->layout == CM_LUT_1D_PACKED_LINEAR) width = (cfg->width == 17) ? 4916 : 35940; REG_UPDATE_2(_3DLUT_FL_CONFIG, diff --git a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c index e4602c3ddc66..57de98444f6c 100644 --- a/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c +++ b/drivers/gpu/drm/amd/display/dc/hubp/dcn42/dcn42_hubp.c @@ -20,6 +20,12 @@ static void hubp42_set_fgcg(struct hubp *hubp, bool enable) { struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp); + /* Temporary workaround for IOMMU mismatch issue. + * Fine grain control via bit1 of debug flag. + */ + if (hubp->ctx->dc->debug.iommu_mismatch_temp_wka & 0x2) + enable = false; + REG_UPDATE(HUBP_CLK_CNTL, HUBP_FGCG_REP_DIS, !enable); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c index 042602c50e35..c9691974bf72 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c @@ -3166,12 +3166,12 @@ static void dce110_program_front_end_for_pipe( plane_state->rotation); /* Moved programming gamma from dc to hwss */ - if (pipe_ctx->plane_state->update_flags.bits.full_update || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change) + if (pipe_ctx->plane_state->update_bits.full_update || + pipe_ctx->plane_state->update_bits.in_transfer_func_change || + pipe_ctx->plane_state->update_bits.gamma_change) hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); - if (pipe_ctx->plane_state->update_flags.bits.full_update) + if (pipe_ctx->plane_state->update_bits.full_update) hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); DC_LOG_SURFACE( diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c index a08e9f9eec17..26aa303b8237 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dce60/dce60_hwseq.c @@ -332,12 +332,12 @@ dce60_program_front_end_for_pipe( plane_state->rotation); /* Moved programming gamma from dc to hwss */ - if (pipe_ctx->plane_state->update_flags.bits.full_update || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change) + if (pipe_ctx->plane_state->update_bits.full_update || + pipe_ctx->plane_state->update_bits.in_transfer_func_change || + pipe_ctx->plane_state->update_bits.gamma_change) hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); - if (pipe_ctx->plane_state->update_flags.bits.full_update) + if (pipe_ctx->plane_state->update_bits.full_update) hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); DC_LOG_SURFACE( diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c index 7112b71af977..541cd908b341 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn10/dcn10_hwseq.c @@ -2981,7 +2981,7 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) mpcc_id = hubp->inst; /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update) { + if (!pipe_ctx->plane_state->update_bits.full_update) { mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); return; @@ -3041,7 +3041,7 @@ static void dcn10_update_dchubp_dpp( /* If request max dpp clk is lower than current dispclk, no need to * divided by 2 */ - if (plane_state->update_flags.bits.full_update) { + if (plane_state->update_bits.full_update) { /* new calculated dispclk, dppclk are stored in * context->bw_ctx.bw.dcn.clk.dispclk_khz / dppclk_khz. current @@ -3096,7 +3096,7 @@ static void dcn10_update_dchubp_dpp( * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG */ - if (plane_state->update_flags.bits.full_update) { + if (plane_state->update_bits.full_update) { hubp->funcs->hubp_vtg_sel(hubp, pipe_ctx->stream_res.tg->inst); hubp->funcs->hubp_setup( @@ -3113,26 +3113,26 @@ static void dcn10_update_dchubp_dpp( size.surface_size = pipe_ctx->plane_res.scl_data.viewport; - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.bpp_change) + if (plane_state->update_bits.full_update || + plane_state->update_bits.bpp_change) dcn10_update_dpp(dpp, plane_state); - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.per_pixel_alpha_change || - plane_state->update_flags.bits.global_alpha_change) + if (plane_state->update_bits.full_update || + plane_state->update_bits.per_pixel_alpha_change || + plane_state->update_bits.global_alpha_change) hws->funcs.update_mpcc(dc, pipe_ctx); - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.per_pixel_alpha_change || - plane_state->update_flags.bits.global_alpha_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change) { + if (plane_state->update_bits.full_update || + plane_state->update_bits.per_pixel_alpha_change || + plane_state->update_bits.global_alpha_change || + plane_state->update_bits.scaling_change || + plane_state->update_bits.position_change) { update_scaler(pipe_ctx); } - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change) { + if (plane_state->update_bits.full_update || + plane_state->update_bits.scaling_change || + plane_state->update_bits.position_change) { hubp->funcs->mem_program_viewport( hubp, &pipe_ctx->plane_res.scl_data.viewport, @@ -3150,7 +3150,7 @@ static void dcn10_update_dchubp_dpp( dc->hwss.set_cursor_sdr_white_level(pipe_ctx); } - if (plane_state->update_flags.bits.full_update) { + if (plane_state->update_bits.full_update) { /*gamut remap*/ dc->hwss.program_gamut_remap(pipe_ctx); @@ -3161,15 +3161,15 @@ static void dcn10_update_dchubp_dpp( pipe_ctx->stream_res.opp->inst); } - if (plane_state->update_flags.bits.full_update || - plane_state->update_flags.bits.pixel_format_change || - plane_state->update_flags.bits.horizontal_mirror_change || - plane_state->update_flags.bits.rotation_change || - plane_state->update_flags.bits.swizzle_change || - plane_state->update_flags.bits.dcc_change || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.plane_size_change) { + if (plane_state->update_bits.full_update || + plane_state->update_bits.pixel_format_change || + plane_state->update_bits.horizontal_mirror_change || + plane_state->update_bits.rotation_change || + plane_state->update_bits.swizzle_change || + plane_state->update_bits.dcc_change || + plane_state->update_bits.bpp_change || + plane_state->update_bits.scaling_change || + plane_state->update_bits.plane_size_change) { hubp->funcs->hubp_program_surface_config( hubp, plane_state->format, @@ -3278,16 +3278,16 @@ void dcn10_program_pipe( hws->funcs.blank_pixel_data(dc, pipe_ctx, blank); } - if (pipe_ctx->plane_state->update_flags.bits.full_update) + if (pipe_ctx->plane_state->update_bits.full_update) dcn10_enable_plane(dc, pipe_ctx, context); dcn10_update_dchubp_dpp(dc, pipe_ctx, context); hws->funcs.set_hdr_multiplier(pipe_ctx); - if (pipe_ctx->plane_state->update_flags.bits.full_update || - pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change) + if (pipe_ctx->plane_state->update_bits.full_update || + pipe_ctx->plane_state->update_bits.in_transfer_func_change || + pipe_ctx->plane_state->update_bits.gamma_change) hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); /* dcn10_translate_regamma_to_hw_format takes 750us to finish @@ -3296,7 +3296,7 @@ void dcn10_program_pipe( * Always call this for now since it does memcmp inside before * doing heavy calculation and programming */ - if (pipe_ctx->plane_state->update_flags.bits.full_update) + if (pipe_ctx->plane_state->update_bits.full_update) hws->funcs.set_output_transfer_func(dc, pipe_ctx, pipe_ctx->stream); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c index e6a8206f8ce0..95e5b6a6ba0f 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c @@ -1066,11 +1066,11 @@ bool dcn20_set_blend_lut( bool result = true; const struct pwl_params *blend_lut = NULL; - if (plane_state->blend_tf.type == TF_TYPE_HWPWL) - blend_lut = &plane_state->blend_tf.pwl; - else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.blend_func.type == TF_TYPE_HWPWL) + blend_lut = &plane_state->cm.blend_func.pwl; + else if (plane_state->cm.blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { cm_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->blend_tf, + &plane_state->cm.blend_func, &dpp_base->regamma_params, false); blend_lut = &dpp_base->regamma_params; } @@ -1086,19 +1086,19 @@ bool dcn20_set_shaper_3dlut( bool result = true; const struct pwl_params *shaper_lut = NULL; - if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL) - shaper_lut = &plane_state->in_shaper_func.pwl; - else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.shaper_func.type == TF_TYPE_HWPWL) + shaper_lut = &plane_state->cm.shaper_func.pwl; + else if (plane_state->cm.shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { cm_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->in_shaper_func, + &plane_state->cm.shaper_func, &dpp_base->shaper_params, true); shaper_lut = &dpp_base->shaper_params; } result = dpp_base->funcs->dpp_program_shaper_lut(dpp_base, shaper_lut); - if (plane_state->lut3d_func.state.bits.initialized == 1) + if (plane_state->cm.lut3d_func.state.bits.initialized == 1) result = dpp_base->funcs->dpp_program_3dlut(dpp_base, - &plane_state->lut3d_func.lut_3d); + &plane_state->cm.lut3d_func.lut_3d); else result = dpp_base->funcs->dpp_program_3dlut(dpp_base, NULL); @@ -1733,10 +1733,10 @@ void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.plane_changed || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.input_csc_change || - plane_state->update_flags.bits.color_space_change || - plane_state->update_flags.bits.coeff_reduction_change) { + plane_state->update_bits.bpp_change || + plane_state->update_bits.input_csc_change || + plane_state->update_bits.color_space_change || + plane_state->update_bits.coeff_reduction_change) { struct dc_bias_and_scale bns_params = plane_state->bias_and_scale; // program the input csc @@ -1760,16 +1760,16 @@ void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.mpcc || pipe_ctx->update_flags.bits.plane_changed - || plane_state->update_flags.bits.global_alpha_change - || plane_state->update_flags.bits.per_pixel_alpha_change) { + || plane_state->update_bits.global_alpha_change + || plane_state->update_bits.per_pixel_alpha_change) { // MPCC inst is equal to pipe index in practice hws->funcs.update_mpcc(dc, pipe_ctx); } if (pipe_ctx->update_flags.bits.scaler || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change || - plane_state->update_flags.bits.per_pixel_alpha_change || + plane_state->update_bits.scaling_change || + plane_state->update_bits.position_change || + plane_state->update_bits.per_pixel_alpha_change || pipe_ctx->stream->update_flags.bits.scaling) { pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP); @@ -1779,8 +1779,8 @@ void dcn20_update_dchubp_dpp( } if (pipe_ctx->update_flags.bits.viewport || - (context == dc->current_state && plane_state->update_flags.bits.position_change) || - (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || + (context == dc->current_state && plane_state->update_bits.position_change) || + (context == dc->current_state && plane_state->update_bits.scaling_change) || (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { hubp->funcs->mem_program_viewport( @@ -1812,7 +1812,7 @@ void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || pipe_ctx->update_flags.bits.plane_changed || pipe_ctx->stream->update_flags.bits.gamut_remap - || plane_state->update_flags.bits.gamut_remap_change + || plane_state->update_bits.gamut_remap_change || pipe_ctx->stream->update_flags.bits.out_csc) { /* dpp/cm gamut remap*/ dc->hwss.program_gamut_remap(pipe_ctx); @@ -1828,14 +1828,14 @@ void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.plane_changed || pipe_ctx->update_flags.bits.opp_changed || - plane_state->update_flags.bits.pixel_format_change || - plane_state->update_flags.bits.horizontal_mirror_change || - plane_state->update_flags.bits.rotation_change || - plane_state->update_flags.bits.swizzle_change || - plane_state->update_flags.bits.dcc_change || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.plane_size_change) { + plane_state->update_bits.pixel_format_change || + plane_state->update_bits.horizontal_mirror_change || + plane_state->update_bits.rotation_change || + plane_state->update_bits.swizzle_change || + plane_state->update_bits.dcc_change || + plane_state->update_bits.bpp_change || + plane_state->update_bits.scaling_change || + plane_state->update_bits.plane_size_change) { struct plane_size size = plane_state->plane_size; size.surface_size = pipe_ctx->plane_res.scl_data.viewport; @@ -1853,7 +1853,7 @@ void dcn20_update_dchubp_dpp( if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.plane_changed || - plane_state->update_flags.bits.addr_update) { + plane_state->update_bits.addr_update) { if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_mall_type == SUBVP_MAIN) { union block_sequence_params params; @@ -1969,18 +1969,18 @@ static void dcn20_program_pipe( } if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw || - pipe_ctx->plane_state->update_flags.raw || + dc_pipe_update_bits_is_any_set(&pipe_ctx->plane_state->update_bits) || pipe_ctx->stream->update_flags.raw)) dcn20_update_dchubp_dpp(dc, pipe_ctx, context); if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable || - pipe_ctx->plane_state->update_flags.bits.hdr_mult)) + pipe_ctx->plane_state->update_bits.hdr_mult)) hws->funcs.set_hdr_multiplier(pipe_ctx); if (pipe_ctx->plane_state && - (pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change || - pipe_ctx->plane_state->update_flags.bits.lut_3d || + (pipe_ctx->plane_state->update_bits.in_transfer_func_change || + pipe_ctx->plane_state->update_bits.gamma_change || + pipe_ctx->plane_state->update_bits.lut_3d || pipe_ctx->update_flags.bits.enable)) hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); @@ -2186,7 +2186,7 @@ void dcn20_program_front_end_for_ctx( pipe = &context->res_ctx.pipe_ctx[i]; if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream && pipe->stream->num_wb_info > 0 - && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw) + && (pipe->update_flags.raw || (pipe->plane_state && dc_pipe_update_bits_is_any_set(&pipe->plane_state->update_bits)) || pipe->stream->update_flags.raw) && hws->funcs.program_all_writeback_pipes_in_tree) hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); @@ -2998,7 +2998,7 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) mpcc_id = hubp->inst; /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update && + if (!pipe_ctx->plane_state->update_bits.full_update && !pipe_ctx->update_flags.bits.mpcc) { mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c index ce18d75fd991..7b820bdae55b 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn201/dcn201_hwseq.c @@ -485,7 +485,7 @@ void dcn201_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) mpcc_id = dpp_id; /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update) { + if (!pipe_ctx->plane_state->update_bits.full_update) { dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); return; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c index a7c85a2302ab..aed9d06ec538 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn30/dcn30_hwseq.c @@ -239,11 +239,13 @@ bool dcn30_set_blend_lut( bool result = true; const struct pwl_params *blend_lut = NULL; - if (plane_state->blend_tf.type == TF_TYPE_HWPWL) - blend_lut = &plane_state->blend_tf.pwl; - else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.blend_func.type == TF_TYPE_HWPWL) + blend_lut = &plane_state->cm.blend_func.pwl; + else if (plane_state->cm.blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->blend_tf, &dpp_base->regamma_params, false); + &plane_state->cm.blend_func, + &dpp_base->regamma_params, + false); if (!result) return result; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c index a3242e7521a4..c2ea25927765 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c @@ -490,12 +490,12 @@ bool dcn32_set_mcm_luts( const struct pwl_params *lut_params = NULL; // 1D LUT - if (plane_state->blend_tf.type == TF_TYPE_HWPWL) - lut_params = &plane_state->blend_tf.pwl; - else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { - result = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->blend_tf, - &dpp_base->regamma_params, false); + if (plane_state->cm.blend_func.type == TF_TYPE_HWPWL) + lut_params = &plane_state->cm.blend_func.pwl; + else if (plane_state->cm.blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { + result = cm3_helper_translate_curve_to_degamma_hw_format( + &plane_state->cm.blend_func, + &dpp_base->regamma_params); if (!result) return result; @@ -505,21 +505,22 @@ bool dcn32_set_mcm_luts( lut_params = NULL; // Shaper - if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL) - lut_params = &plane_state->in_shaper_func.pwl; - else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.shaper_func.type == TF_TYPE_HWPWL) + lut_params = &plane_state->cm.shaper_func.pwl; + else if (plane_state->cm.shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { // TODO: dpp_base replace rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->in_shaper_func, - &dpp_base->shaper_params, true); + &plane_state->cm.shaper_func, + &dpp_base->shaper_params, + true); lut_params = rval ? &dpp_base->shaper_params : NULL; } mpc->funcs->program_shaper(mpc, lut_params, mpcc_id); // 3D - if (plane_state->lut3d_func.state.bits.initialized == 1) - result = mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id); + if (plane_state->cm.lut3d_func.state.bits.initialized == 1) + result = mpc->funcs->program_3dlut(mpc, &plane_state->cm.lut3d_func.lut_3d, mpcc_id); else result = mpc->funcs->program_3dlut(mpc, NULL, mpcc_id); @@ -551,9 +552,8 @@ bool dcn32_set_input_transfer_func(struct dc *dc, if (plane_state->in_transfer_func.type == TF_TYPE_HWPWL) params = &plane_state->in_transfer_func.pwl; else if (plane_state->in_transfer_func.type == TF_TYPE_DISTRIBUTED_POINTS && - cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->in_transfer_func, - &dpp_base->degamma_params, false)) + cm3_helper_translate_curve_to_degamma_hw_format(&plane_state->in_transfer_func, + &dpp_base->degamma_params)) params = &dpp_base->degamma_params; dpp_base->funcs->dpp_program_gamcor_lut(dpp_base, params); @@ -1463,7 +1463,7 @@ void dcn32_update_phantom_vp_position(struct dc *dc, if (pipe->stream && dc_state_get_pipe_subvp_type(context, pipe) == SUBVP_MAIN && dc_state_get_paired_subvp_stream(context, pipe->stream) == phantom_pipe->stream) { - if (pipe->plane_state && pipe->plane_state->update_flags.bits.position_change) { + if (pipe->plane_state && pipe->plane_state->update_bits.position_change) { phantom_plane->src_rect.x = pipe->plane_state->src_rect.x; phantom_plane->src_rect.y = pipe->plane_state->src_rect.y; @@ -1471,7 +1471,7 @@ void dcn32_update_phantom_vp_position(struct dc *dc, phantom_plane->dst_rect.x = pipe->plane_state->dst_rect.x; phantom_plane->dst_rect.y = pipe->plane_state->dst_rect.y; - phantom_pipe->plane_state->update_flags.bits.position_change = 1; + phantom_pipe->plane_state->update_bits.position_change = 1; resource_build_scaling_params(phantom_pipe); return; } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c index 8f9038fec0f7..01027d120cb0 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c @@ -581,9 +581,6 @@ void dcn35_power_down_on_boot(struct dc *dc) bool dcn35_apply_idle_power_optimizations(struct dc *dc, bool enable) { - if (dc->debug.dmcub_emulation) - return true; - if (enable) { uint32_t num_active_edp = 0; int i; diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index 96815a92a629..0336d118e77e 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -321,7 +321,7 @@ void dcn401_init_hw(struct dc *dc) user_level = link->panel_cntl->stored_backlight_registers.USER_LEVEL; } - if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) { + if (link->force_to_use_aux) { struct graphics_object_i2c_info i2c_info; struct ddc *ddc_pin; struct gpio_ddc_hw_info hw_info; @@ -410,37 +410,27 @@ static void dcn401_get_mcm_lut_xable_from_pipe_ctx(struct dc *dc, struct pipe_ct enum MCM_LUT_XABLE *lut3d_xable, enum MCM_LUT_XABLE *lut1d_xable) { - enum dc_cm2_shaper_3dlut_setting shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL; - bool lut1d_enable = false; struct mpc *mpc = dc->res_pool->mpc; int mpcc_id = pipe_ctx->plane_res.hubp->inst; if (!pipe_ctx->plane_state) return; - shaper_3dlut_setting = pipe_ctx->plane_state->mcm_shaper_3dlut_setting; - lut1d_enable = pipe_ctx->plane_state->mcm_lut1d_enable; + mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id); pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE; - *lut1d_xable = lut1d_enable ? MCM_LUT_ENABLE : MCM_LUT_DISABLE; - - switch (shaper_3dlut_setting) { - case DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL: - *lut3d_xable = *shaper_xable = MCM_LUT_DISABLE; - break; - case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER: - *lut3d_xable = MCM_LUT_DISABLE; - *shaper_xable = MCM_LUT_ENABLE; - break; - case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT: - *lut3d_xable = *shaper_xable = MCM_LUT_ENABLE; - break; - } + *lut1d_xable = pipe_ctx->plane_state->cm.flags.bits.blend_enable ? + MCM_LUT_ENABLE : MCM_LUT_DISABLE; + *shaper_xable = pipe_ctx->plane_state->cm.flags.bits.shaper_enable ? + MCM_LUT_ENABLE : MCM_LUT_DISABLE; + *lut3d_xable = (pipe_ctx->plane_state->cm.flags.bits.shaper_enable && + pipe_ctx->plane_state->cm.flags.bits.lut3d_enable) ? + MCM_LUT_ENABLE : MCM_LUT_DISABLE; } void dcn401_populate_mcm_luts(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_cm2_func_luts mcm_luts, + const struct dc_plane_cm *cm, bool lut_bank_a) { struct dpp *dpp_base = pipe_ctx->plane_res.dpp; @@ -448,14 +438,17 @@ void dcn401_populate_mcm_luts(struct dc *dc, int mpcc_id = hubp->inst; struct mpc *mpc = dc->res_pool->mpc; union mcm_lut_params m_lut_params; - enum dc_cm2_transfer_func_source lut3d_src = mcm_luts.lut3d_data.lut3d_src; + const bool lut3d_dma = !!cm->flags.bits.lut3d_dma_enable; enum hubp_3dlut_fl_format format = 0; enum hubp_3dlut_fl_mode mode; - enum hubp_3dlut_fl_width width = 0; + /* Width was previously hard-coded to TRANSFORMED via local_mcm build, + * preserve identical behavior. + */ + enum hubp_3dlut_fl_width width = hubp_3dlut_fl_width_transformed; enum hubp_3dlut_fl_addressing_mode addr_mode; - enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g = 0; - enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b = 0; - enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r = 0; + enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g; + enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b; + enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r; enum MCM_LUT_XABLE shaper_xable = MCM_LUT_DISABLE; enum MCM_LUT_XABLE lut3d_xable = MCM_LUT_DISABLE; enum MCM_LUT_XABLE lut1d_xable = MCM_LUT_DISABLE; @@ -464,13 +457,13 @@ void dcn401_populate_mcm_luts(struct dc *dc, dcn401_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable); /* 1D LUT */ - if (mcm_luts.lut1d_func) { + { memset(&m_lut_params, 0, sizeof(m_lut_params)); - if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL) - m_lut_params.pwl = &mcm_luts.lut1d_func->pwl; - else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) { + if (cm->blend_func.type == TF_TYPE_HWPWL) + m_lut_params.pwl = &cm->blend_func.pwl; + else if (cm->blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx, - mcm_luts.lut1d_func, + &cm->blend_func, &dpp_base->regamma_params, false); m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL; } @@ -483,14 +476,14 @@ void dcn401_populate_mcm_luts(struct dc *dc, } /* Shaper */ - if (mcm_luts.shaper && mcm_luts.lut3d_data.mpc_3dlut_enable) { + if (cm->flags.bits.lut3d_enable) { memset(&m_lut_params, 0, sizeof(m_lut_params)); - if (mcm_luts.shaper->type == TF_TYPE_HWPWL) - m_lut_params.pwl = &mcm_luts.shaper->pwl; - else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { + if (cm->shaper_func.type == TF_TYPE_HWPWL) + m_lut_params.pwl = &cm->shaper_func.pwl; + else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { ASSERT(false); rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx, - mcm_luts.shaper, + &cm->shaper_func, &dpp_base->regamma_params, true); m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL; } @@ -503,42 +496,43 @@ void dcn401_populate_mcm_luts(struct dc *dc, } /* 3DLUT */ - switch (lut3d_src) { - case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM: + if (!lut3d_dma) { + /* SYSMEM (legacy lut3d_func) */ memset(&m_lut_params, 0, sizeof(m_lut_params)); if (hubp->funcs->hubp_enable_3dlut_fl) hubp->funcs->hubp_enable_3dlut_fl(hubp, false); - if (mcm_luts.lut3d_data.lut3d_func && mcm_luts.lut3d_data.lut3d_func->state.bits.initialized) { - m_lut_params.lut3d = &mcm_luts.lut3d_data.lut3d_func->lut_3d; + if (cm->lut3d_func.state.bits.initialized) { + m_lut_params.lut3d = &cm->lut3d_func.lut_3d; if (mpc->funcs->populate_lut) mpc->funcs->populate_lut(mpc, MCM_LUT_3DLUT, m_lut_params, lut_bank_a, mpcc_id); if (mpc->funcs->program_lut_mode) mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id); } - break; - case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM: - switch (mcm_luts.lut3d_data.gpu_mem_params.size) { - case DC_CM2_GPU_MEM_SIZE_333333: + } else { + /* VIDMEM (3DLUT DMA Fast Load) */ + + /* Select width based on the requested LUT size */ + switch (cm->lut3d_dma.size) { +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) + case CM_LUT_SIZE_333333: if (dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_33) width = hubp_3dlut_fl_width_33; break; - case DC_CM2_GPU_MEM_SIZE_171717: +#endif // CONFIG_DRM_AMD_DC_DCN4_2 + case CM_LUT_SIZE_171717: width = hubp_3dlut_fl_width_17; break; - case DC_CM2_GPU_MEM_SIZE_TRANSFORMED: - width = hubp_3dlut_fl_width_transformed; - break; default: - //TODO: handle default case + /* keep default hubp_3dlut_fl_width_transformed */ break; } //check for support if (mpc->funcs->mcm.is_config_supported && !mpc->funcs->mcm.is_config_supported(width)) - break; + return; if (mpc->funcs->program_lut_read_write_control) mpc->funcs->program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, mpcc_id); @@ -546,21 +540,24 @@ void dcn401_populate_mcm_luts(struct dc *dc, mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id); if (hubp->funcs->hubp_program_3dlut_fl_addr) - hubp->funcs->hubp_program_3dlut_fl_addr(hubp, mcm_luts.lut3d_data.gpu_mem_params.addr); + hubp->funcs->hubp_program_3dlut_fl_addr(hubp, cm->lut3d_dma.addr); + /* bit_depth was previously zero-initialized in local_mcm, + * preserve identical behavior. + */ if (mpc->funcs->mcm.program_bit_depth) - mpc->funcs->mcm.program_bit_depth(mpc, mcm_luts.lut3d_data.gpu_mem_params.bit_depth, mpcc_id); + mpc->funcs->mcm.program_bit_depth(mpc, 0, mpcc_id); - switch (mcm_luts.lut3d_data.gpu_mem_params.layout) { - case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB: + switch (cm->lut3d_dma.swizzle) { + case CM_LUT_3D_SWIZZLE_LINEAR_RGB: mode = hubp_3dlut_fl_mode_native_1; addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; break; - case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR: + case CM_LUT_3D_SWIZZLE_LINEAR_BGR: mode = hubp_3dlut_fl_mode_native_2; addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; break; - case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR: + case CM_LUT_1D_PACKED_LINEAR: mode = hubp_3dlut_fl_mode_transform; addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear; break; @@ -575,40 +572,38 @@ void dcn401_populate_mcm_luts(struct dc *dc, if (hubp->funcs->hubp_program_3dlut_fl_addressing_mode) hubp->funcs->hubp_program_3dlut_fl_addressing_mode(hubp, addr_mode); - switch (mcm_luts.lut3d_data.gpu_mem_params.format_params.format) { - case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB: + switch (cm->lut3d_dma.format) { + case CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB: format = hubp_3dlut_fl_format_unorm_12msb_bitslice; break; - case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB: + case CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB: format = hubp_3dlut_fl_format_unorm_12lsb_bitslice; break; - case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10: + case CM_LUT_PIXEL_FORMAT_RGBA16161616_FLOAT_FP1_5_10: format = hubp_3dlut_fl_format_float_fp1_5_10; break; + default: + break; } if (hubp->funcs->hubp_program_3dlut_fl_format) hubp->funcs->hubp_program_3dlut_fl_format(hubp, format); if (hubp->funcs->hubp_update_3dlut_fl_bias_scale && mpc->funcs->mcm.program_bias_scale) { mpc->funcs->mcm.program_bias_scale(mpc, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale, + cm->lut3d_dma.bias, + cm->lut3d_dma.scale, mpcc_id); hubp->funcs->hubp_update_3dlut_fl_bias_scale(hubp, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale); + cm->lut3d_dma.bias, + cm->lut3d_dma.scale); } - //navi 4x has a bug and r and blue are swapped and need to be worked around here in - //TODO: need to make a method for get_xbar per asic OR do the workaround in program_crossbar for 4x - switch (mcm_luts.lut3d_data.gpu_mem_params.component_order) { - case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA: - default: - crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15; - crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31; - crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47; - break; - } + /* component_order was previously hard-coded to RGBA in local_mcm, + * preserve identical behavior. + */ + crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15; + crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31; + crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47; if (hubp->funcs->hubp_program_3dlut_fl_crossbar) hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp, @@ -634,8 +629,6 @@ void dcn401_populate_mcm_luts(struct dc *dc, mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id); } } - break; - } } @@ -660,19 +653,19 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx, const struct pwl_params *lut_params = NULL; bool rval; - if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) { - dcn401_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a); + if (plane_state->cm.flags.bits.lut3d_dma_enable) { + dcn401_populate_mcm_luts(dc, pipe_ctx, &plane_state->cm, plane_state->lut_bank_a); return true; } mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id); pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE; // 1D LUT - if (plane_state->blend_tf.type == TF_TYPE_HWPWL) - lut_params = &plane_state->blend_tf.pwl; - else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.blend_func.type == TF_TYPE_HWPWL) + lut_params = &plane_state->cm.blend_func.pwl; + else if (plane_state->cm.blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->blend_tf, + &plane_state->cm.blend_func, &dpp_base->regamma_params, false); lut_params = rval ? &dpp_base->regamma_params : NULL; } @@ -680,12 +673,12 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx, lut_params = NULL; // Shaper - if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL) - lut_params = &plane_state->in_shaper_func.pwl; - else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.shaper_func.type == TF_TYPE_HWPWL) + lut_params = &plane_state->cm.shaper_func.pwl; + else if (plane_state->cm.shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { // TODO: dpp_base replace rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->in_shaper_func, + &plane_state->cm.shaper_func, &dpp_base->shaper_params, true); lut_params = rval ? &dpp_base->shaper_params : NULL; } @@ -693,8 +686,8 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx, // 3D if (mpc->funcs->program_3dlut) { - if (plane_state->lut3d_func.state.bits.initialized == 1) - result &= mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id); + if (plane_state->cm.lut3d_func.state.bits.initialized == 1) + result &= mpc->funcs->program_3dlut(mpc, &plane_state->cm.lut3d_func.lut_3d, mpcc_id); else result &= mpc->funcs->program_3dlut(mpc, NULL, mpcc_id); } @@ -1428,7 +1421,7 @@ void dcn401_wait_for_dcc_meta_propagation(const struct dc *dc, if (pipe_ctx->plane_state && pipe_ctx->plane_state->dcc.enable && pipe_ctx->plane_state->flip_immediate && - pipe_ctx->plane_state->update_flags.bits.addr_update) { + pipe_ctx->plane_state->update_bits.addr_update) { is_wait_needed = true; break; } @@ -1503,6 +1496,57 @@ void dcn401_prepare_bandwidth(struct dc *dc, } } +void dcn401_prepare_bandwidth_sequence(struct dc *dc, + struct dc_state *context, + struct block_sequence_state *seq_state) +{ + struct hubbub *hubbub = dc->res_pool->hubbub; + bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support; + unsigned int compbuf_size = 0; + + /* Any transition into P-State support should disable MCLK switching first to avoid hangs */ + if (p_state_change_support) { + dc->optimized_required = true; + context->bw_ctx.bw.dcn.clk.p_state_change_support = false; + } + + if (dc->clk_mgr->dc_mode_softmax_enabled) + if (dc->clk_mgr->clks.dramclk_khz <= (int)dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && + context->bw_ctx.bw.dcn.clk.dramclk_khz > (int)dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) + hwss_add_clk_mgr_set_max_memclk(seq_state, dc->clk_mgr, + dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz); + + /* Build bandwidth and display clocks back-to-back (SW calc + append BLS steps) */ + if (dc->clk_mgr->funcs->build_clock_update_for_bls) + dc->clk_mgr->funcs->build_clock_update_for_bls( + dc->clk_mgr, context, false, seq_state); + + hwss_add_hubbub_program_watermarks(seq_state, dc, hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + false); + + if (hubbub->funcs->program_arbiter) + hwss_add_hubbub_program_arbiter(seq_state, dc, hubbub, + &context->bw_ctx.bw.dcn.arb_regs, false); + + if (hubbub->funcs->program_compbuf_segments) { + compbuf_size = context->bw_ctx.bw.dcn.arb_regs.compbuf_size; + dc->optimized_required |= (compbuf_size != dc->current_state->bw_ctx.bw.dcn.arb_regs.compbuf_size); + + hwss_add_hubbub_program_compbuf_segments(seq_state, hubbub, compbuf_size, false); + } + + if (dc->debug.fams2_config.bits.enable) { + dcn401_dmub_hw_control_lock(dc, context, true); + dcn401_fams2_update_config(dc, context, false); + dcn401_dmub_hw_control_lock(dc, context, false); + } + + if (p_state_change_support != context->bw_ctx.bw.dcn.clk.p_state_change_support) + context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support; +} + void dcn401_optimize_bandwidth( struct dc *dc, struct dc_state *context) @@ -1556,6 +1600,50 @@ void dcn401_optimize_bandwidth( } } +/* + * optimize_bandwidth_sequence is unused for now. It will be used when + * dc_commit_state_no_check is moved into block sequence pattern, similar + * to how commit_planes_do_stream_update_sequence replaces + * commit_planes_do_stream_update. + */ +void dcn401_optimize_bandwidth_sequence(struct dc *dc, + struct dc_state *context, + struct block_sequence_state *seq_state) +{ + struct hubbub *hubbub = dc->res_pool->hubbub; + + /* enable fams2 if needed */ + if (dc->debug.fams2_config.bits.enable) { + dcn401_dmub_hw_control_lock(dc, context, true); + dcn401_fams2_update_config(dc, context, true); + dcn401_dmub_hw_control_lock(dc, context, false); + } + + hwss_add_hubbub_program_watermarks(seq_state, dc, hubbub, + &context->bw_ctx.bw.dcn.watermarks, + dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, + true); + + if (hubbub->funcs->program_arbiter) + hwss_add_hubbub_program_arbiter(seq_state, dc, hubbub, + &context->bw_ctx.bw.dcn.arb_regs, true); + + if (dc->clk_mgr->dc_mode_softmax_enabled) + if (dc->clk_mgr->clks.dramclk_khz > (int)dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 && + context->bw_ctx.bw.dcn.clk.dramclk_khz <= (int)dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000) + hwss_add_clk_mgr_set_max_memclk(seq_state, dc->clk_mgr, + dc->clk_mgr->bw_params->dc_mode_softmax_memclk); + + if (hubbub->funcs->program_compbuf_segments) + hwss_add_hubbub_program_compbuf_segments(seq_state, hubbub, + context->bw_ctx.bw.dcn.arb_regs.compbuf_size, true); + + /* Build bandwidth and display clocks (SW calc + append BLS steps) */ + if (dc->clk_mgr->funcs->build_clock_update_for_bls) + dc->clk_mgr->funcs->build_clock_update_for_bls( + dc->clk_mgr, context, true, seq_state); +} + void dcn401_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock) @@ -1999,10 +2087,9 @@ void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx) for (odm_pipe = pipe_ctx; odm_pipe != NULL; odm_pipe = odm_pipe->next_odm_pipe) { for (mpc_pipe = odm_pipe; mpc_pipe != NULL; mpc_pipe = mpc_pipe->bottom_pipe) { - if (mpc_pipe->plane_state && mpc_pipe->plane_state->mcm_luts.lut3d_data.lut3d_src - == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM - && mpc_pipe->plane_state->mcm_shaper_3dlut_setting - == DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT) { + if (mpc_pipe->plane_state && + mpc_pipe->plane_state->cm.flags.bits.lut3d_enable && + mpc_pipe->plane_state->cm.flags.bits.lut3d_dma_enable) { wa_pipes[wa_pipe_ct++] = mpc_pipe; } } @@ -2276,18 +2363,18 @@ void dcn401_program_pipe( } if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw || - pipe_ctx->plane_state->update_flags.raw || + dc_pipe_update_bits_is_any_set(&pipe_ctx->plane_state->update_bits) || pipe_ctx->stream->update_flags.raw)) dc->hwss.update_dchubp_dpp(dc, pipe_ctx, context); if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable || - pipe_ctx->plane_state->update_flags.bits.hdr_mult)) + pipe_ctx->plane_state->update_bits.hdr_mult)) hws->funcs.set_hdr_multiplier(pipe_ctx); if (pipe_ctx->plane_state && - (pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change || - pipe_ctx->plane_state->update_flags.bits.lut_3d || + (pipe_ctx->plane_state->update_bits.in_transfer_func_change || + pipe_ctx->plane_state->update_bits.gamma_change || + pipe_ctx->plane_state->update_bits.lut_3d || pipe_ctx->update_flags.bits.enable)) hws->funcs.set_input_transfer_func(dc, pipe_ctx, pipe_ctx->plane_state); @@ -2346,7 +2433,7 @@ void dcn401_program_pipe( pipe_ctx->stream_res.test_pattern_params.offset); } if (pipe_ctx->plane_state - && pipe_ctx->plane_state->update_flags.bits.cm_hist_change + && pipe_ctx->plane_state->update_bits.cm_hist_change && hws->funcs.program_cm_hist) hws->funcs.program_cm_hist(dc, pipe_ctx, pipe_ctx->plane_state); } @@ -2427,7 +2514,7 @@ void dcn401_program_pipe_sequence( } if (pipe_ctx->plane_state && (pipe_ctx->update_flags.raw || - pipe_ctx->plane_state->update_flags.raw || + dc_pipe_update_bits_is_any_set(&pipe_ctx->plane_state->update_bits) || pipe_ctx->stream->update_flags.raw)) { if (dc->hwss.update_dchubp_dpp_sequence) @@ -2435,15 +2522,15 @@ void dcn401_program_pipe_sequence( } if (pipe_ctx->plane_state && (pipe_ctx->update_flags.bits.enable || - pipe_ctx->plane_state->update_flags.bits.hdr_mult)) { + pipe_ctx->plane_state->update_bits.hdr_mult)) { hws->funcs.set_hdr_multiplier_sequence(pipe_ctx, seq_state); } if (pipe_ctx->plane_state && - (pipe_ctx->plane_state->update_flags.bits.in_transfer_func_change || - pipe_ctx->plane_state->update_flags.bits.gamma_change || - pipe_ctx->plane_state->update_flags.bits.lut_3d || + (pipe_ctx->plane_state->update_bits.in_transfer_func_change || + pipe_ctx->plane_state->update_bits.gamma_change || + pipe_ctx->plane_state->update_bits.lut_3d || pipe_ctx->update_flags.bits.enable)) { hwss_add_dpp_set_input_transfer_func(seq_state, dc, pipe_ctx, pipe_ctx->plane_state); @@ -2501,7 +2588,7 @@ void dcn401_program_pipe_sequence( } if (pipe_ctx->plane_state - && pipe_ctx->plane_state->update_flags.bits.cm_hist_change + && pipe_ctx->plane_state->update_bits.cm_hist_change && hws->funcs.program_cm_hist) { hwss_add_dpp_program_cm_hist(seq_state, pipe_ctx->plane_res.dpp, @@ -2655,7 +2742,7 @@ void dcn401_program_front_end_for_ctx( pipe = &context->res_ctx.pipe_ctx[i]; if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream && pipe->stream->num_wb_info > 0 - && (pipe->update_flags.raw || (pipe->plane_state && pipe->plane_state->update_flags.raw) + && (pipe->update_flags.raw || (pipe->plane_state && dc_pipe_update_bits_is_any_set(&pipe->plane_state->update_bits)) || pipe->stream->update_flags.raw) && hws->funcs.program_all_writeback_pipes_in_tree) hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context); @@ -3741,10 +3828,10 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, /* Step 7: DPP setup - input CSC and format setup */ if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.plane_changed || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.input_csc_change || - plane_state->update_flags.bits.color_space_change || - plane_state->update_flags.bits.coeff_reduction_change) { + plane_state->update_bits.bpp_change || + plane_state->update_bits.input_csc_change || + plane_state->update_bits.color_space_change || + plane_state->update_bits.coeff_reduction_change) { hwss_add_dpp_setup_dpp(seq_state, pipe_ctx); /* Step 8: DPP cursor matrix setup */ @@ -3761,8 +3848,8 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, /* Step 10: MPCC updates */ if (pipe_ctx->update_flags.bits.mpcc || pipe_ctx->update_flags.bits.plane_changed || - plane_state->update_flags.bits.global_alpha_change || - plane_state->update_flags.bits.per_pixel_alpha_change) { + plane_state->update_bits.global_alpha_change || + plane_state->update_bits.per_pixel_alpha_change) { /* Check if update_mpcc_sequence is implemented and prefer it over single MPC_UPDATE_MPCC step */ if (hws->funcs.update_mpcc_sequence) @@ -3771,9 +3858,9 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, /* Step 11: DPP scaler setup */ if (pipe_ctx->update_flags.bits.scaler || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.position_change || - plane_state->update_flags.bits.per_pixel_alpha_change || + plane_state->update_bits.scaling_change || + plane_state->update_bits.position_change || + plane_state->update_bits.per_pixel_alpha_change || pipe_ctx->stream->update_flags.bits.scaling) { pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->plane_state->per_pixel_alpha; ASSERT(pipe_ctx->plane_res.scl_data.lb_params.depth == LB_PIXEL_DEPTH_36BPP); @@ -3782,8 +3869,8 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, /* Step 12: HUBP viewport programming */ if (pipe_ctx->update_flags.bits.viewport || - (context == dc->current_state && plane_state->update_flags.bits.position_change) || - (context == dc->current_state && plane_state->update_flags.bits.scaling_change) || + (context == dc->current_state && plane_state->update_bits.position_change) || + (context == dc->current_state && plane_state->update_bits.scaling_change) || (context == dc->current_state && pipe_ctx->stream->update_flags.bits.scaling)) { hwss_add_hubp_mem_program_viewport(seq_state, hubp, &pipe_ctx->plane_res.scl_data.viewport, &pipe_ctx->plane_res.scl_data.viewport_c); @@ -3815,7 +3902,7 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.opp_changed || pipe_ctx->update_flags.bits.plane_changed || pipe_ctx->stream->update_flags.bits.gamut_remap || - plane_state->update_flags.bits.gamut_remap_change || + plane_state->update_bits.gamut_remap_change || pipe_ctx->stream->update_flags.bits.out_csc) { /* Gamut remap */ @@ -3830,14 +3917,14 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.plane_changed || pipe_ctx->update_flags.bits.opp_changed || - plane_state->update_flags.bits.pixel_format_change || - plane_state->update_flags.bits.horizontal_mirror_change || - plane_state->update_flags.bits.rotation_change || - plane_state->update_flags.bits.swizzle_change || - plane_state->update_flags.bits.dcc_change || - plane_state->update_flags.bits.bpp_change || - plane_state->update_flags.bits.scaling_change || - plane_state->update_flags.bits.plane_size_change) { + plane_state->update_bits.pixel_format_change || + plane_state->update_bits.horizontal_mirror_change || + plane_state->update_bits.rotation_change || + plane_state->update_bits.swizzle_change || + plane_state->update_bits.dcc_change || + plane_state->update_bits.bpp_change || + plane_state->update_bits.scaling_change || + plane_state->update_bits.plane_size_change) { struct plane_size size = plane_state->plane_size; size.surface_size = pipe_ctx->plane_res.scl_data.viewport; @@ -3851,7 +3938,7 @@ void dcn401_update_dchubp_dpp_sequence(struct dc *dc, /* Step 19: Update plane address (with SubVP support) */ if (pipe_ctx->update_flags.bits.enable || pipe_ctx->update_flags.bits.plane_changed || - plane_state->update_flags.bits.addr_update) { + plane_state->update_bits.addr_update) { /* SubVP save surface address if needed */ if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_mall_type == SUBVP_MAIN) { @@ -3924,7 +4011,7 @@ void dcn401_update_mpcc_sequence(struct dc *dc, mpcc_id = hubp->inst; /* Step 1: Update blending if no full update needed */ - if (!pipe_ctx->plane_state->update_flags.bits.full_update && + if (!pipe_ctx->plane_state->update_bits.full_update && !pipe_ctx->update_flags.bits.mpcc) { /* Update blending configuration */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h index f78162ab859b..a760050eea8c 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.h @@ -52,7 +52,7 @@ enum dc_status dcn401_enable_stream_timing( void dcn401_enable_stream(struct pipe_ctx *pipe_ctx); void dcn401_populate_mcm_luts(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_cm2_func_luts mcm_luts, + const struct dc_plane_cm *cm, bool lut_bank_a); void dcn401_setup_hpo_hw_control(const struct dce_hwseq *hws, bool enable); @@ -70,10 +70,20 @@ void dcn401_wait_for_dcc_meta_propagation(const struct dc *dc, void dcn401_prepare_bandwidth(struct dc *dc, struct dc_state *context); +struct block_sequence_state; + +void dcn401_prepare_bandwidth_sequence(struct dc *dc, + struct dc_state *context, + struct block_sequence_state *seq_state); + void dcn401_optimize_bandwidth( struct dc *dc, struct dc_state *context); +void dcn401_optimize_bandwidth_sequence(struct dc *dc, + struct dc_state *context, + struct block_sequence_state *seq_state); + void dcn401_dmub_hw_control_lock(struct dc *dc, struct dc_state *context, bool lock); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c index 33b2cf344f1e..f206e221f926 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_init.c @@ -44,7 +44,9 @@ static const struct hw_sequencer_funcs dcn401_funcs = { .interdependent_update_lock = dcn401_interdependent_update_lock, .cursor_lock = dcn10_cursor_lock, .prepare_bandwidth = dcn401_prepare_bandwidth, + .prepare_bandwidth_sequence = dcn401_prepare_bandwidth_sequence, .optimize_bandwidth = dcn401_optimize_bandwidth, + .optimize_bandwidth_sequence = dcn401_optimize_bandwidth_sequence, .update_bandwidth = dcn401_update_bandwidth, .set_drr = dcn10_set_drr, .get_position = dcn10_get_position, diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c index 664004cadf10..f415473517d4 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.c @@ -70,6 +70,7 @@ void dcn42_init_hw(struct dc *dc) uint32_t user_level = MAX_BACKLIGHT_LEVEL; bool dchub_ref_freq_changed; int current_dchub_ref_freq = 0; + uint8_t dcfclk_gate_dis_value = 0; if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) { dc->clk_mgr->funcs->init_clocks(dc->clk_mgr); @@ -243,7 +244,13 @@ void dcn42_init_hw(struct dc *dc) /* enable all DCN clock gating */ REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); - REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + /* Temporary workaround for IOMMU mismatch issue. + * Fine grain control via bit0 of debug flag. + */ + if (dc->debug.iommu_mismatch_temp_wka & 0x1) + dcfclk_gate_dis_value = 1; + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, dcfclk_gate_dis_value); } dcn401_setup_hpo_hw_control(hws, true); @@ -348,7 +355,7 @@ void dcn42_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) mpcc_id = hubp->inst; /* If there is no full update, don't need to touch MPC tree*/ - if (!pipe_ctx->plane_state->update_flags.bits.full_update && + if (!pipe_ctx->plane_state->update_bits.full_update && !pipe_ctx->update_flags.bits.mpcc) { mpc->funcs->update_blending(mpc, &blnd_cfg, mpcc_id); dc->hwss.update_visual_confirm_color(dc, pipe_ctx, mpcc_id); @@ -394,40 +401,33 @@ void dcn42_program_cm_hist( } static void dc_get_lut_xbar( - enum dc_cm2_gpu_mem_pixel_component_order order, enum hubp_3dlut_fl_crossbar_bit_slice *cr_r, enum hubp_3dlut_fl_crossbar_bit_slice *y_g, enum hubp_3dlut_fl_crossbar_bit_slice *cb_b) { - switch (order) { - case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_RGBA: - *cr_r = hubp_3dlut_fl_crossbar_bit_slice_32_47; - *y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31; - *cb_b = hubp_3dlut_fl_crossbar_bit_slice_0_15; - break; - case DC_CM2_GPU_MEM_PIXEL_COMPONENT_ORDER_BGRA: - *cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15; - *y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31; - *cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47; - break; - } + /* component_order was previously hard-coded to RGBA in local_mcm, + * preserve identical behavior. + */ + *cr_r = hubp_3dlut_fl_crossbar_bit_slice_32_47; + *y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31; + *cb_b = hubp_3dlut_fl_crossbar_bit_slice_0_15; } static void dc_get_lut_mode( - enum dc_cm2_gpu_mem_layout layout, + enum dc_cm_lut_swizzle swizzle, enum hubp_3dlut_fl_mode *mode, enum hubp_3dlut_fl_addressing_mode *addr_mode) { - switch (layout) { - case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB: + switch (swizzle) { + case CM_LUT_3D_SWIZZLE_LINEAR_RGB: *mode = hubp_3dlut_fl_mode_native_1; *addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; break; - case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR: + case CM_LUT_3D_SWIZZLE_LINEAR_BGR: *mode = hubp_3dlut_fl_mode_native_2; *addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; break; - case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR: + case CM_LUT_1D_PACKED_LINEAR: *mode = hubp_3dlut_fl_mode_transform; *addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear; break; @@ -439,19 +439,22 @@ static void dc_get_lut_mode( } static void dc_get_lut_format( - enum dc_cm2_gpu_mem_format dc_format, + enum dc_cm_lut_pixel_format dc_format, enum hubp_3dlut_fl_format *format) { switch (dc_format) { - case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB: + case CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB: *format = hubp_3dlut_fl_format_unorm_12msb_bitslice; break; - case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB: + case CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB: *format = hubp_3dlut_fl_format_unorm_12lsb_bitslice; break; - case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10: + case CM_LUT_PIXEL_FORMAT_RGBA16161616_FLOAT_FP1_5_10: *format = hubp_3dlut_fl_format_float_fp1_5_10; break; + default: + *format = hubp_3dlut_fl_format_unorm_12msb_bitslice; + break; } } @@ -465,16 +468,17 @@ static bool dc_is_rmcm_3dlut_supported(struct hubp *hubp, struct mpc *mpc) return false; } -static bool is_rmcm_3dlut_fl_supported(struct dc *dc, enum dc_cm2_gpu_mem_size size) +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) +static bool is_rmcm_3dlut_fl_supported(struct dc *dc) { + /* size was previously hard-coded to TRANSFORMED in local_mcm, + * which mapped to dim_17. Preserve identical behavior. + */ if (!dc->caps.color.mpc.rmcm_3d_lut_caps.dma_3d_lut) return false; - if (size == DC_CM2_GPU_MEM_SIZE_171717) - return dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_17 != 0u; - else if (size == DC_CM2_GPU_MEM_SIZE_333333) - return dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_33 != 0u; - return false; + return dc->caps.color.mpc.rmcm_3d_lut_caps.lut_dim_caps.dim_17 != 0u; } +#endif static void dcn42_set_mcm_location_post_blend(struct dc *dc, struct pipe_ctx *pipe_ctx, bool bPostBlend) { @@ -495,56 +499,45 @@ static void dcn42_get_mcm_lut_xable_from_pipe_ctx(struct dc *dc, struct pipe_ctx enum MCM_LUT_XABLE *lut3d_xable, enum MCM_LUT_XABLE *lut1d_xable) { - enum dc_cm2_shaper_3dlut_setting shaper_3dlut_setting = DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL; - bool lut1d_enable = false; struct mpc *mpc = dc->res_pool->mpc; int mpcc_id = pipe_ctx->plane_res.hubp->inst; if (!pipe_ctx->plane_state) return; - shaper_3dlut_setting = pipe_ctx->plane_state->mcm_shaper_3dlut_setting; - lut1d_enable = pipe_ctx->plane_state->mcm_lut1d_enable; + mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id); pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE; - *lut1d_xable = lut1d_enable ? MCM_LUT_ENABLE : MCM_LUT_DISABLE; - - switch (shaper_3dlut_setting) { - case DC_CM2_SHAPER_3DLUT_SETTING_BYPASS_ALL: - *lut3d_xable = *shaper_xable = MCM_LUT_DISABLE; - break; - case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER: - *lut3d_xable = MCM_LUT_DISABLE; - *shaper_xable = MCM_LUT_ENABLE; - break; - case DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT: - *lut3d_xable = *shaper_xable = MCM_LUT_ENABLE; - break; - } + *lut1d_xable = pipe_ctx->plane_state->cm.flags.bits.blend_enable ? + MCM_LUT_ENABLE : MCM_LUT_DISABLE; + *shaper_xable = pipe_ctx->plane_state->cm.flags.bits.shaper_enable ? + MCM_LUT_ENABLE : MCM_LUT_DISABLE; + *lut3d_xable = (pipe_ctx->plane_state->cm.flags.bits.shaper_enable && + pipe_ctx->plane_state->cm.flags.bits.lut3d_enable) ? + MCM_LUT_ENABLE : MCM_LUT_DISABLE; } static void fl_get_lut_mode( - enum dc_cm2_gpu_mem_layout layout, - enum dc_cm2_gpu_mem_size size, + enum dc_cm_lut_swizzle swizzle, enum hubp_3dlut_fl_mode *mode, enum hubp_3dlut_fl_addressing_mode *addr_mode, enum hubp_3dlut_fl_width *width) { + /* size was previously hard-coded to TRANSFORMED in local_mcm, + * preserve identical behavior (transformed width). + */ *width = hubp_3dlut_fl_width_17; - if (size == DC_CM2_GPU_MEM_SIZE_333333) - *width = hubp_3dlut_fl_width_33; - - switch (layout) { - case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_RGB: + switch (swizzle) { + case CM_LUT_3D_SWIZZLE_LINEAR_RGB: *mode = hubp_3dlut_fl_mode_native_1; *addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; break; - case DC_CM2_GPU_MEM_LAYOUT_3D_SWIZZLE_LINEAR_BGR: + case CM_LUT_3D_SWIZZLE_LINEAR_BGR: *mode = hubp_3dlut_fl_mode_native_2; *addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; break; - case DC_CM2_GPU_MEM_LAYOUT_1D_PACKED_LINEAR: + case CM_LUT_1D_PACKED_LINEAR: *mode = hubp_3dlut_fl_mode_transform; *addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear; break; @@ -558,8 +551,7 @@ static void fl_get_lut_mode( bool dcn42_program_rmcm_luts( struct hubp *hubp, struct pipe_ctx *pipe_ctx, - enum dc_cm2_transfer_func_source lut3d_src, - struct dc_cm2_func_luts *mcm_luts, + const struct dc_plane_cm *cm, struct mpc *mpc, bool lut_bank_a, int mpcc_id) @@ -589,21 +581,24 @@ bool dcn42_program_rmcm_luts( if (!rmcm_3dlut) return false; - rmcm_3dlut->protection_bits = mcm_luts->lut3d_data.rmcm_tmz; + /* rmcm_tmz was previously zero-initialized in local_mcm, + * preserve identical behavior. + */ + rmcm_3dlut->protection_bits = 0; dcn42_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable); /* Shaper */ - if (mcm_luts->shaper) { + { memset(&m_lut_params, 0, sizeof(m_lut_params)); - if (mcm_luts->shaper->type == TF_TYPE_HWPWL) { - m_lut_params.pwl = &mcm_luts->shaper->pwl; - } else if (mcm_luts->shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { + if (cm->shaper_func.type == TF_TYPE_HWPWL) { + m_lut_params.pwl = &cm->shaper_func.pwl; + } else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { ASSERT(false); cm_helper_translate_curve_to_hw_format( dc->ctx, - mcm_luts->shaper, + &cm->shaper_func, &dpp_base->shaper_params, true); m_lut_params.pwl = &dpp_base->shaper_params; } @@ -619,15 +614,16 @@ bool dcn42_program_rmcm_luts( } /* 3DLUT */ - switch (lut3d_src) { - case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM: + if (!cm->flags.bits.lut3d_dma_enable) { + /* SYSMEM path — no DMA 3DLUT available. + * Previously this was treated as a no-op for the DMA/VIDMEM + * programming, preserve identical behavior. + */ memset(&m_lut_params, 0, sizeof(m_lut_params)); - // Don't know what to do in this case. - //case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM: - break; - case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM: - fl_get_lut_mode(mcm_luts->lut3d_data.gpu_mem_params.layout, - mcm_luts->lut3d_data.gpu_mem_params.size, + } else { + /* VIDMEM (3DLUT DMA Fast Load) */ + + fl_get_lut_mode(cm->lut3d_dma.swizzle, &mode, &addr_mode, &width); @@ -639,20 +635,19 @@ bool dcn42_program_rmcm_luts( return false; // setting native or transformed mode, - dc_get_lut_mode(mcm_luts->lut3d_data.gpu_mem_params.layout, &mode, &addr_mode); + dc_get_lut_mode(cm->lut3d_dma.swizzle, &mode, &addr_mode); //seems to be only for the MCM - dc_get_lut_format(mcm_luts->lut3d_data.gpu_mem_params.format_params.format, &format); + dc_get_lut_format(cm->lut3d_dma.format, &format); dc_get_lut_xbar( - mcm_luts->lut3d_data.gpu_mem_params.component_order, &crossbar_bit_slice_cr_r, &crossbar_bit_slice_y_g, &crossbar_bit_slice_cb_b); fl_config.mode = mode; fl_config.enabled = lut3d_xable != MCM_LUT_DISABLE; - fl_config.address = mcm_luts->lut3d_data.gpu_mem_params.addr; + fl_config.address = cm->lut3d_dma.addr; fl_config.format = format; fl_config.crossbar_bit_slice_y_g = crossbar_bit_slice_y_g; fl_config.crossbar_bit_slice_cb_b = crossbar_bit_slice_cb_b; @@ -660,17 +655,20 @@ bool dcn42_program_rmcm_luts( fl_config.width = width; fl_config.protection_bits = rmcm_3dlut->protection_bits; fl_config.addr_mode = addr_mode; - fl_config.layout = mcm_luts->lut3d_data.gpu_mem_params.layout; - fl_config.bias = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.bias; - fl_config.scale = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.scale; + fl_config.layout = cm->lut3d_dma.swizzle; + fl_config.bias = cm->lut3d_dma.bias; + fl_config.scale = cm->lut3d_dma.scale; mpc_fl_config.enabled = fl_config.enabled; mpc_fl_config.width = width; mpc_fl_config.select_lut_bank_a = lut_bank_a; - mpc_fl_config.bit_depth = mcm_luts->lut3d_data.gpu_mem_params.bit_depth; + /* bit_depth was previously zero-initialized in local_mcm, + * preserve identical behavior. + */ + mpc_fl_config.bit_depth = 0; mpc_fl_config.hubp_index = hubp->inst; - mpc_fl_config.bias = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.bias; - mpc_fl_config.scale = mcm_luts->lut3d_data.gpu_mem_params.format_params.float_params.scale; + mpc_fl_config.bias = cm->lut3d_dma.bias; + mpc_fl_config.scale = cm->lut3d_dma.scale; //1. power down the block mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, false); @@ -682,10 +680,6 @@ bool dcn42_program_rmcm_luts( //3. power on the block mpc->funcs->rmcm.power_on_shaper_3dlut(mpc, mpcc_id, true); - - break; - default: - return false; } return true; @@ -693,7 +687,7 @@ bool dcn42_program_rmcm_luts( void dcn42_populate_mcm_luts(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_cm2_func_luts mcm_luts, + const struct dc_plane_cm *cm, bool lut_bank_a) { struct dpp *dpp_base = pipe_ctx->plane_res.dpp; @@ -701,14 +695,17 @@ void dcn42_populate_mcm_luts(struct dc *dc, int mpcc_id = hubp->inst; struct mpc *mpc = dc->res_pool->mpc; union mcm_lut_params m_lut_params; - enum dc_cm2_transfer_func_source lut3d_src = mcm_luts.lut3d_data.lut3d_src; + const bool lut3d_dma = !!cm->flags.bits.lut3d_dma_enable; enum hubp_3dlut_fl_format format = 0; enum hubp_3dlut_fl_mode mode; - enum hubp_3dlut_fl_width width = 0; + /* Width was previously hard-coded to TRANSFORMED via local_mcm build, + * preserve identical behavior. + */ + enum hubp_3dlut_fl_width width = hubp_3dlut_fl_width_transformed; enum hubp_3dlut_fl_addressing_mode addr_mode; - enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g = 0; - enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b = 0; - enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r = 0; + enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g; + enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b; + enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cr_r; enum MCM_LUT_XABLE shaper_xable = MCM_LUT_DISABLE; enum MCM_LUT_XABLE lut3d_xable = MCM_LUT_DISABLE; enum MCM_LUT_XABLE lut1d_xable = MCM_LUT_DISABLE; @@ -717,33 +714,35 @@ void dcn42_populate_mcm_luts(struct dc *dc, dcn42_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable); //MCM - setting its location (Before/After) blender - //set to post blend (true) + //mpc_mcm_post_blend was previously zero-initialized in local_mcm, + //preserve identical behavior. dcn42_set_mcm_location_post_blend( dc, pipe_ctx, - mcm_luts.lut3d_data.mpc_mcm_post_blend); + false); //RMCM - 3dLUT+Shaper - if (mcm_luts.lut3d_data.rmcm_3dlut_enable && - is_rmcm_3dlut_fl_supported(dc, mcm_luts.lut3d_data.gpu_mem_params.size)) { +#if defined(CONFIG_DRM_AMD_DC_DCN4_2) + if (cm->flags.bits.rmcm_enable && + is_rmcm_3dlut_fl_supported(dc)) { dcn42_program_rmcm_luts( hubp, pipe_ctx, - lut3d_src, - &mcm_luts, + cm, mpc, lut_bank_a, mpcc_id); } +#endif /* CONFIG_DRM_AMD_DC_DCN4_2 */ /* 1D LUT */ - if (mcm_luts.lut1d_func) { + { memset(&m_lut_params, 0, sizeof(m_lut_params)); - if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL) - m_lut_params.pwl = &mcm_luts.lut1d_func->pwl; - else if (mcm_luts.lut1d_func->type == TF_TYPE_DISTRIBUTED_POINTS) { + if (cm->blend_func.type == TF_TYPE_HWPWL) + m_lut_params.pwl = &cm->blend_func.pwl; + else if (cm->blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx, - mcm_luts.lut1d_func, + &cm->blend_func, &dpp_base->regamma_params, false); m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL; } @@ -756,14 +755,14 @@ void dcn42_populate_mcm_luts(struct dc *dc, } /* Shaper */ - if (mcm_luts.shaper && mcm_luts.lut3d_data.mpc_3dlut_enable) { + if (cm->flags.bits.lut3d_enable) { memset(&m_lut_params, 0, sizeof(m_lut_params)); - if (mcm_luts.shaper->type == TF_TYPE_HWPWL) - m_lut_params.pwl = &mcm_luts.shaper->pwl; - else if (mcm_luts.shaper->type == TF_TYPE_DISTRIBUTED_POINTS) { + if (cm->shaper_func.type == TF_TYPE_HWPWL) + m_lut_params.pwl = &cm->shaper_func.pwl; + else if (cm->shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { ASSERT(false); rval = cm3_helper_translate_curve_to_hw_format(mpc->ctx, - mcm_luts.shaper, + &cm->shaper_func, &dpp_base->regamma_params, true); m_lut_params.pwl = rval ? &dpp_base->regamma_params : NULL; } @@ -776,41 +775,27 @@ void dcn42_populate_mcm_luts(struct dc *dc, } /* 3DLUT */ - switch (lut3d_src) { - case DC_CM2_TRANSFER_FUNC_SOURCE_SYSMEM: + if (!lut3d_dma) { + /* SYSMEM (legacy lut3d_func) */ memset(&m_lut_params, 0, sizeof(m_lut_params)); if (hubp->funcs->hubp_enable_3dlut_fl) hubp->funcs->hubp_enable_3dlut_fl(hubp, false); - if (mcm_luts.lut3d_data.lut3d_func && mcm_luts.lut3d_data.lut3d_func->state.bits.initialized) { - m_lut_params.lut3d = &mcm_luts.lut3d_data.lut3d_func->lut_3d; + if (cm->lut3d_func.state.bits.initialized) { + m_lut_params.lut3d = &cm->lut3d_func.lut_3d; if (mpc->funcs->populate_lut) mpc->funcs->populate_lut(mpc, MCM_LUT_3DLUT, m_lut_params, lut_bank_a, mpcc_id); if (mpc->funcs->program_lut_mode) mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id); } - break; - case DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM: - switch (mcm_luts.lut3d_data.gpu_mem_params.size) { - case DC_CM2_GPU_MEM_SIZE_333333: - width = hubp_3dlut_fl_width_33; - break; - case DC_CM2_GPU_MEM_SIZE_171717: - width = hubp_3dlut_fl_width_17; - break; - case DC_CM2_GPU_MEM_SIZE_TRANSFORMED: - width = hubp_3dlut_fl_width_transformed; - break; - default: - //TODO: Handle default case - break; - } + } else { + /* VIDMEM (3DLUT DMA Fast Load) */ //check for support if (mpc->funcs->mcm.is_config_supported && !mpc->funcs->mcm.is_config_supported(width)) - break; + return; if (mpc->funcs->program_lut_read_write_control) mpc->funcs->program_lut_read_write_control(mpc, MCM_LUT_3DLUT, lut_bank_a, mpcc_id); @@ -818,49 +803,70 @@ void dcn42_populate_mcm_luts(struct dc *dc, mpc->funcs->program_lut_mode(mpc, MCM_LUT_3DLUT, lut3d_xable, lut_bank_a, mpcc_id); if (hubp->funcs->hubp_program_3dlut_fl_addr) - hubp->funcs->hubp_program_3dlut_fl_addr(hubp, mcm_luts.lut3d_data.gpu_mem_params.addr); + hubp->funcs->hubp_program_3dlut_fl_addr(hubp, cm->lut3d_dma.addr); + /* bit_depth was previously zero-initialized in local_mcm, + * preserve identical behavior. + */ if (mpc->funcs->mcm.program_bit_depth) - mpc->funcs->mcm.program_bit_depth(mpc, mcm_luts.lut3d_data.gpu_mem_params.bit_depth, mpcc_id); + mpc->funcs->mcm.program_bit_depth(mpc, 0, mpcc_id); - dc_get_lut_mode(mcm_luts.lut3d_data.gpu_mem_params.layout, &mode, &addr_mode); + switch (cm->lut3d_dma.swizzle) { + case CM_LUT_3D_SWIZZLE_LINEAR_RGB: + mode = hubp_3dlut_fl_mode_native_1; + addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; + break; + case CM_LUT_3D_SWIZZLE_LINEAR_BGR: + mode = hubp_3dlut_fl_mode_native_2; + addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; + break; + case CM_LUT_1D_PACKED_LINEAR: + mode = hubp_3dlut_fl_mode_transform; + addr_mode = hubp_3dlut_fl_addressing_mode_simple_linear; + break; + default: + mode = hubp_3dlut_fl_mode_disable; + addr_mode = hubp_3dlut_fl_addressing_mode_sw_linear; + break; + } if (hubp->funcs->hubp_program_3dlut_fl_mode) hubp->funcs->hubp_program_3dlut_fl_mode(hubp, mode); if (hubp->funcs->hubp_program_3dlut_fl_addressing_mode) hubp->funcs->hubp_program_3dlut_fl_addressing_mode(hubp, addr_mode); - switch (mcm_luts.lut3d_data.gpu_mem_params.format_params.format) { - case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12MSB: + switch (cm->lut3d_dma.format) { + case CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12MSB: format = hubp_3dlut_fl_format_unorm_12msb_bitslice; break; - case DC_CM2_GPU_MEM_FORMAT_16161616_UNORM_12LSB: + case CM_LUT_PIXEL_FORMAT_RGBA16161616_UNORM_12LSB: format = hubp_3dlut_fl_format_unorm_12lsb_bitslice; break; - case DC_CM2_GPU_MEM_FORMAT_16161616_FLOAT_FP1_5_10: + case CM_LUT_PIXEL_FORMAT_RGBA16161616_FLOAT_FP1_5_10: format = hubp_3dlut_fl_format_float_fp1_5_10; break; + default: + break; } if (hubp->funcs->hubp_program_3dlut_fl_format) hubp->funcs->hubp_program_3dlut_fl_format(hubp, format); if (hubp->funcs->hubp_update_3dlut_fl_bias_scale && mpc->funcs->mcm.program_bias_scale) { mpc->funcs->mcm.program_bias_scale(mpc, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale, + cm->lut3d_dma.bias, + cm->lut3d_dma.scale, mpcc_id); hubp->funcs->hubp_update_3dlut_fl_bias_scale(hubp, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.bias, - mcm_luts.lut3d_data.gpu_mem_params.format_params.float_params.scale); + cm->lut3d_dma.bias, + cm->lut3d_dma.scale); } - //navi 4x has a bug and r and blue are swapped and need to be worked around here in - //TODO: need to make a method for get_xbar per asic OR do the workaround in program_crossbar for 4x - dc_get_lut_xbar( - mcm_luts.lut3d_data.gpu_mem_params.component_order, - &crossbar_bit_slice_cr_r, - &crossbar_bit_slice_y_g, - &crossbar_bit_slice_cb_b); + /* component_order was previously hard-coded to RGBA in local_mcm, + * preserve identical behavior. + */ + crossbar_bit_slice_cr_r = hubp_3dlut_fl_crossbar_bit_slice_0_15; + crossbar_bit_slice_y_g = hubp_3dlut_fl_crossbar_bit_slice_16_31; + crossbar_bit_slice_cb_b = hubp_3dlut_fl_crossbar_bit_slice_32_47; if (hubp->funcs->hubp_program_3dlut_fl_crossbar) hubp->funcs->hubp_program_3dlut_fl_crossbar(hubp, @@ -886,7 +892,6 @@ void dcn42_populate_mcm_luts(struct dc *dc, mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, MCM_LUT_DISABLE, lut_bank_a, mpcc_id); } } - break; } } @@ -901,19 +906,19 @@ bool dcn42_set_mcm_luts(struct pipe_ctx *pipe_ctx, const struct pwl_params *lut_params = NULL; bool rval; - if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) { - dcn42_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a); + if (plane_state->cm.flags.bits.lut3d_dma_enable) { + dcn42_populate_mcm_luts(dc, pipe_ctx, &plane_state->cm, plane_state->lut_bank_a); return true; } mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id); pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE; // 1D LUT - if (plane_state->blend_tf.type == TF_TYPE_HWPWL) - lut_params = &plane_state->blend_tf.pwl; - else if (plane_state->blend_tf.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.blend_func.type == TF_TYPE_HWPWL) + lut_params = &plane_state->cm.blend_func.pwl; + else if (plane_state->cm.blend_func.type == TF_TYPE_DISTRIBUTED_POINTS) { rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->blend_tf, + &plane_state->cm.blend_func, &dpp_base->regamma_params, false); lut_params = rval ? &dpp_base->regamma_params : NULL; } @@ -921,12 +926,12 @@ bool dcn42_set_mcm_luts(struct pipe_ctx *pipe_ctx, lut_params = NULL; // Shaper - if (plane_state->in_shaper_func.type == TF_TYPE_HWPWL) - lut_params = &plane_state->in_shaper_func.pwl; - else if (plane_state->in_shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { + if (plane_state->cm.shaper_func.type == TF_TYPE_HWPWL) + lut_params = &plane_state->cm.shaper_func.pwl; + else if (plane_state->cm.shaper_func.type == TF_TYPE_DISTRIBUTED_POINTS) { // TODO: dpp_base replace rval = cm3_helper_translate_curve_to_hw_format(plane_state->ctx, - &plane_state->in_shaper_func, + &plane_state->cm.shaper_func, &dpp_base->shaper_params, true); lut_params = rval ? &dpp_base->shaper_params : NULL; } @@ -934,8 +939,8 @@ bool dcn42_set_mcm_luts(struct pipe_ctx *pipe_ctx, // 3D if (mpc->funcs->program_3dlut) { - if (plane_state->lut3d_func.state.bits.initialized == 1) - result &= mpc->funcs->program_3dlut(mpc, &plane_state->lut3d_func.lut_3d, mpcc_id); + if (plane_state->cm.lut3d_func.state.bits.initialized == 1) + result &= mpc->funcs->program_3dlut(mpc, &plane_state->cm.lut3d_func.lut_3d, mpcc_id); else result &= mpc->funcs->program_3dlut(mpc, NULL, mpcc_id); } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h index 0539ee0ffaee..c469e7535114 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn42/dcn42_hwseq.h @@ -20,14 +20,13 @@ bool dcn42_set_mcm_luts(struct pipe_ctx *pipe_ctx, void dcn42_populate_mcm_luts(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_cm2_func_luts mcm_luts, + const struct dc_plane_cm *cm, bool lut_bank_a); bool dcn42_program_rmcm_luts( struct hubp *hubp, struct pipe_ctx *pipe_ctx, - enum dc_cm2_transfer_func_source lut3d_src, - struct dc_cm2_func_luts *mcm_luts, + const struct dc_plane_cm *cm, struct mpc *mpc, bool lut_bank_a, int mpcc_id); diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h index dfb278a9fc3e..65df8002d3d7 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h @@ -894,6 +894,36 @@ struct disable_audio_stream_params { struct pipe_ctx *pipe_ctx; }; +struct clk_mgr_set_max_memclk_params { + struct clk_mgr *clk_mgr; + unsigned int memclk_mhz; +}; + +struct clk_mgr_update_clocks_params { + struct clk_mgr *clk_mgr; +}; + +struct hubbub_program_watermarks_params { + struct dc *dc; + struct hubbub *hubbub; + union dcn_watermark_set *watermarks; + unsigned int refclk_mhz; + bool safe_to_lower; +}; + +struct hubbub_program_arbiter_params { + struct dc *dc; + struct hubbub *hubbub; + struct dml2_display_arb_regs *arb_regs; + bool safe_to_lower; +}; + +struct hubbub_program_compbuf_segments_params { + struct hubbub *hubbub; + unsigned int compbuf_size; + bool safe_to_lower; +}; + struct prepare_bandwidth_params { struct dc *dc; struct dc_state *context; @@ -1057,6 +1087,11 @@ union block_sequence_params { struct disable_audio_stream_params disable_audio_stream_params; struct prepare_bandwidth_params prepare_bandwidth_params; struct link_set_dpms_on_params link_set_dpms_on_params; + struct clk_mgr_set_max_memclk_params clk_mgr_set_max_memclk_params; + struct clk_mgr_update_clocks_params clk_mgr_update_clocks_params; + struct hubbub_program_watermarks_params hubbub_program_watermarks_params; + struct hubbub_program_arbiter_params hubbub_program_arbiter_params; + struct hubbub_program_compbuf_segments_params hubbub_program_compbuf_segments_params; }; enum block_sequence_func { @@ -1209,6 +1244,11 @@ enum block_sequence_func { DISABLE_AUDIO_STREAM, PREPARE_BANDWIDTH, LINK_SET_DPMS_ON, + CLK_MGR_SET_MAX_MEMCLK, + CLK_MGR_UPDATE_CLOCKS, + HUBBUB_PROGRAM_WATERMARKS, + HUBBUB_PROGRAM_ARBITER, + HUBBUB_PROGRAM_COMPBUF_SEGMENTS, /* This must be the last value in this enum, add new ones above */ HWSS_BLOCK_SEQUENCE_FUNC_COUNT }; @@ -1316,8 +1356,14 @@ struct hw_sequencer_funcs { /* Bandwidth Related */ void (*prepare_bandwidth)(struct dc *dc, struct dc_state *context); + void (*prepare_bandwidth_sequence)(struct dc *dc, + struct dc_state *context, + struct block_sequence_state *seq_state); bool (*update_bandwidth)(struct dc *dc, struct dc_state *context); void (*optimize_bandwidth)(struct dc *dc, struct dc_state *context); + void (*optimize_bandwidth_sequence)(struct dc *dc, + struct dc_state *context, + struct block_sequence_state *seq_state); /* Infopacket Related */ void (*set_avmute)(struct pipe_ctx *pipe_ctx, bool enable); @@ -2475,4 +2521,40 @@ void hwss_add_link_set_dpms_on(struct block_sequence_state *seq_state, struct dc_state *state, struct pipe_ctx *pipe_ctx); +/* Clock manager BLS executor functions */ +void hwss_clk_mgr_set_max_memclk(union block_sequence_params *params); +void hwss_clk_mgr_update_clocks(union block_sequence_params *params); + +void hwss_hubbub_program_watermarks(union block_sequence_params *params); + +void hwss_hubbub_program_arbiter(union block_sequence_params *params); + +void hwss_hubbub_program_compbuf_segments(union block_sequence_params *params); + +/* Clock manager BLS add-helper functions */ +void hwss_add_clk_mgr_set_max_memclk(struct block_sequence_state *seq_state, + struct clk_mgr *clk_mgr, + unsigned int memclk_mhz); + +void hwss_add_clk_mgr_update_clocks(struct block_sequence_state *seq_state, + struct clk_mgr *clk_mgr); + +void hwss_add_hubbub_program_watermarks(struct block_sequence_state *seq_state, + struct dc *dc, + struct hubbub *hubbub, + union dcn_watermark_set *watermarks, + unsigned int refclk_mhz, + bool safe_to_lower); + +void hwss_add_hubbub_program_arbiter(struct block_sequence_state *seq_state, + struct dc *dc, + struct hubbub *hubbub, + struct dml2_display_arb_regs *arb_regs, + bool safe_to_lower); + +void hwss_add_hubbub_program_compbuf_segments(struct block_sequence_state *seq_state, + struct hubbub *hubbub, + unsigned int compbuf_size, + bool safe_to_lower); + #endif /* __DC_HW_SEQUENCER_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h index 63c6c841c681..b4956893ae9a 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h +++ b/drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h @@ -58,6 +58,7 @@ struct dc_state; struct dc_stream_status; struct dc_writeback_info; struct dchub_init_data; +struct dc_plane_cm; struct dc_static_screen_params; struct resource_pool; struct resource_context; @@ -219,7 +220,7 @@ struct hwseq_private_funcs { struct dc_state *context); void (*populate_mcm_luts)(struct dc *dc, struct pipe_ctx *pipe_ctx, - struct dc_cm2_func_luts mcm_luts, + const struct dc_plane_cm *cm, bool lut_bank_a); void (*perform_3dlut_wa_unlock)(struct pipe_ctx *pipe_ctx); void (*wait_for_pipe_update_if_needed)(struct dc *dc, struct pipe_ctx *pipe_ctx, bool is_surface_update_only); diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h index f829ce3f70e5..68dc2d4ba7ca 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h @@ -30,6 +30,7 @@ #include "dc.h" #include "core_types.h" #include "dm_pp_smu.h" +struct utm_qos_model; /* Constants */ #define DDR4_DRAM_WIDTH 64 @@ -311,6 +312,7 @@ struct clk_bw_params { struct wm_table wm_table; struct dummy_pstate_entry dummy_pstate_table[4]; struct clk_limit_table_entry dc_mode_limit; + const struct utm_qos_model *utm_qos_model; }; /* Public interfaces */ @@ -318,6 +320,8 @@ struct clk_states { uint32_t dprefclk_khz; }; +struct block_sequence_state; + struct clk_mgr_funcs { /* * This function should set new clocks based on the input "safe_to_lower". @@ -337,6 +341,8 @@ struct clk_mgr_funcs { void (*exit_low_power_state)(struct clk_mgr *clk_mgr); bool (*is_ips_supported)(struct clk_mgr *clk_mgr); + void (*set_idle_power_optimizations)(struct clk_mgr *clk_mgr, bool enable); + void (*init_clocks)(struct clk_mgr *clk_mgr); void (*dump_clk_registers)(struct clk_state_registers_and_bypass *regs_and_bypass, @@ -405,6 +411,12 @@ struct clk_mgr_funcs { void (*get_requested_memory_qos)( struct clk_mgr *clk_mgr, struct dc_requested_memory_qos *qos); + + void (*build_clock_update_for_bls)(struct clk_mgr *clk_mgr, + struct dc_state *context, bool safe_to_lower, + struct block_sequence_state *seq_state); + + void (*execute_clk_mgr_block_sequence)(struct clk_mgr *clk_mgr); }; struct clk_mgr { diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h index 6db7c8753081..e756719308ab 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h @@ -348,6 +348,7 @@ struct dccg_funcs { void (*dccg_root_gate_disable_control)(struct dccg *dccg, uint32_t pipe_idx, uint32_t disable_clock_gating); void (*dccg_read_reg_state)(struct dccg *dccg, struct dcn_dccg_reg_state *dccg_reg_state); void (*dccg_enable_global_fgcg)(struct dccg *dccg, bool enable); + bool (*dccg_get_global_fgcg_status)(struct dccg *dccg); }; #endif //__DAL_DCCG_H__ diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h index 1c18898aa475..6d6eda0e7e9d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h @@ -108,7 +108,7 @@ struct hubp_fl_3dlut_config { uint16_t scale; struct dc_plane_address address; enum hubp_3dlut_fl_addressing_mode addr_mode; - enum dc_cm2_gpu_mem_layout layout; + enum dc_cm_lut_swizzle layout; uint8_t protection_bits; enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_y_g; enum hubp_3dlut_fl_crossbar_bit_slice crossbar_bit_slice_cb_b; diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_service.h b/drivers/gpu/drm/amd/display/dc/inc/link_service.h index 23202c2114bb..addeb3e3b25a 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_service.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_service.h @@ -193,6 +193,7 @@ struct link_service { struct aux_payload *payload); bool (*is_in_aux_transaction_mode)(struct ddc_service *ddc); uint32_t (*get_aux_defer_delay)(struct ddc_service *ddc); + uint8_t (*get_ddc_aux_inst)(const struct dc_link *link); /*************************** DP Capability ****************************/ diff --git a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h index 7a1ecb8d986f..6d15ccdc7f87 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h +++ b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h @@ -536,23 +536,4 @@ uint32_t generic_indirect_reg_update_ex_sync(const struct dc_context *ctx, uint8_t shift1, uint32_t mask1, uint32_t field_value1, ...); -/* register offload macros - * - * instead of MMIO to register directly, in some cases we want - * to gather register sequence and execute the register sequence - * from another thread so we optimize time required for lengthy ops - */ - -/* start gathering register sequence */ -#define REG_SEQ_START() \ - reg_sequence_start_gather(CTX) - -/* start execution of register sequence gathered since REG_SEQ_START */ -#define REG_SEQ_SUBMIT() \ - reg_sequence_start_execute(CTX) - -/* wait for the last REG_SEQ_SUBMIT to finish */ -#define REG_SEQ_WAIT_DONE() \ - reg_sequence_wait_done(CTX) - #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_REG_HELPER_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/soc_and_ip_translator.h b/drivers/gpu/drm/amd/display/dc/inc/soc_and_ip_translator.h index 6a97a3e28bd2..5dcb9f8f4daf 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/soc_and_ip_translator.h +++ b/drivers/gpu/drm/amd/display/dc/inc/soc_and_ip_translator.h @@ -8,26 +8,12 @@ #include "dc.h" #include "dml_top_soc_parameter_types.h" -/* Forward declarations — callers that dereference these structs must include - * the full UTM model headers themselves. */ -struct utm_qos_model; -struct utm_qos_model_dchub_v2; - struct soc_and_ip_translator_funcs { void (*get_soc_bb)( struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config); void (*get_ip_caps)(struct dml2_ip_capabilities *dml_ip_caps); - /** - * get_utm_qos_model - Return the static UTM QoS model for this DCN - * generation. Caller provides storage for @qos_model and @dchub. - * @qos_model: output — populated with SoC bounding box and SOP table - * @dchub: output — populated with DCHUB client extension data - */ - void (*get_utm_qos_model)( - struct utm_qos_model *qos_model, - struct utm_qos_model_dchub_v2 *dchub); }; struct soc_and_ip_translator { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index a3212fd151d1..281a7c5acaca 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -933,7 +933,7 @@ static bool should_verify_link_capability_destructively(struct dc_link *link, destrictive = true; if (is_hdmi_frl_in_use(link)) { destrictive = false; - } else if (link->dc->config.skip_frl_pretraining) { + } else if (link->local_sink->edid_caps.panel_patch.skip_frl_pre_training) { for (i = 0; i < MAX_PIPES; i++) { if (pipes[i].stream != NULL && pipes[i].stream->link == link) { @@ -1164,8 +1164,11 @@ static bool detect_link_and_local_sink(struct dc_link *link, link->link_enc->features.flags.bits.DP_IS_USB_C == 1) { /* if alt mode times out, return false */ - if (!wait_for_entering_dp_alt_mode(link)) + if (!wait_for_entering_dp_alt_mode(link)) { + if (prev_sink) + dc_sink_release(prev_sink); return false; + } } if (!detect_dp(link, &sink_caps, reason)) { diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index b6262e43ca02..67ce8d95bbd6 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -143,6 +143,7 @@ static void construct_link_service_ddc(struct link_service *link_srv) link_aux_transfer_with_retries_no_mutex; link_srv->is_in_aux_transaction_mode = link_is_in_aux_transaction_mode; link_srv->get_aux_defer_delay = link_get_aux_defer_delay; + link_srv->get_ddc_aux_inst = link_get_ddc_aux_inst; } /* link dp capability implements dp specific link capability retrieval sequence. @@ -441,7 +442,7 @@ static enum channel_id get_ddc_line(struct dc_link *link) channel = CHANNEL_ID_UNKNOWN; - if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) { + if (link->force_to_use_aux) { channel = link->aux_hw_inst + 1; } else { ddc = get_ddc_pin(link->ddc); @@ -576,6 +577,8 @@ static bool construct_phy(struct dc_link *link, link->is_internal_display = (disp_connect_caps_info.INTERNAL_DISPLAY != 0); DC_LOG_DC("BIOS object table - is_internal_display: %d", link->is_internal_display); link->no_ddc_pin = disp_connect_caps_info.NO_DDC_PIN != 0; + link->force_to_use_aux = link->dc->config.dp_connector_no_native_i2c + && link->no_ddc_pin; } if (link->link_id.type != OBJECT_TYPE_CONNECTOR) { @@ -598,7 +601,7 @@ static bool construct_phy(struct dc_link *link, goto ddc_create_fail; } - if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) { + if (link->force_to_use_aux) { link->ddc_hw_inst = link->aux_hw_inst; } else { /* Embedded display connectors such as LVDS may not have DDC. */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c index ead71f6d116d..f9d5a2441e38 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c @@ -120,8 +120,7 @@ static void ddc_service_construct( ddc_service->link = init_data->link; ddc_service->ctx = init_data->ctx; - if (ddc_service->link && ddc_service->ctx->dc->config.dp_connector_no_native_i2c && - ddc_service->link->no_ddc_pin) { + if (ddc_service->link && ddc_service->link->force_to_use_aux) { // Obtain aux instance info from i2c_info without GPIO DDC pin info if (dcb->funcs->get_connector_aux_info(dcb, init_data->id, &i2c_info) == BP_RESULT_OK) ddc_service->link->aux_hw_inst = (uint8_t)i2c_info.i2c_line; @@ -252,6 +251,21 @@ static uint32_t defer_delay_converter_wa( #define DP_TRANSLATOR_DELAY 5 +/** + * link_get_ddc_aux_inst - Return the AUX/DDC hardware instance for a link. + * @link: the link to query + * + * Return: aux_hw_inst when I2C is forced over AUX, otherwise the DDC pin + * channel index. + */ +uint8_t link_get_ddc_aux_inst(const struct dc_link *link) +{ + if (link->force_to_use_aux) + return link->aux_hw_inst; + ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF); + return (uint8_t)link->ddc->ddc_pin->hw_info.ddc_channel; +} + uint32_t link_get_aux_defer_delay(struct ddc_service *ddc) { uint32_t defer_delay = 0; @@ -526,7 +540,7 @@ bool try_to_configure_aux_timeout(struct ddc_service *ddc, if (ddc->link->ep_type != DISPLAY_ENDPOINT_PHY) return true; - if (ddc->ctx->dc->config.dp_connector_no_native_i2c && ddc->link->no_ddc_pin) { + if (ddc->link->force_to_use_aux) { if (ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]->funcs->configure_timeout) { ddc->ctx->dc->res_pool->engines[ddc->link->aux_hw_inst]->funcs->configure_timeout(ddc, timeout); result = true; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h index f2a80e12494b..fdd8a3dce97f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h @@ -46,6 +46,8 @@ void set_ddc_transaction_type( struct ddc_service *ddc, enum ddc_transaction_type type); +uint8_t link_get_ddc_aux_inst(const struct dc_link *link); + uint32_t link_get_aux_defer_delay(struct ddc_service *ddc); bool link_is_in_aux_transaction_mode(struct ddc_service *ddc); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index 47abb4066709..d2329714408a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -181,6 +181,12 @@ uint32_t link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw) return 40000000; case 0b110: return 48000000; + case 0b111: + return 64000000; + case 0b1000: + return 80000000; + case 0b1001: + return 96000000; } return 0; @@ -2242,10 +2248,14 @@ void detect_edp_sink_caps(struct dc_link *link) /* * ALPM is only valid for eDP v1.4 or higher. */ - if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14) + if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14) { core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP, &link->dpcd_caps.alpm_caps.raw, sizeof(link->dpcd_caps.alpm_caps.raw)); + core_link_read_dpcd(link, DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_CAP, + &link->dpcd_caps.psr_info.psr_active_vtotal_control_cap, + sizeof(link->dpcd_caps.psr_info.psr_active_vtotal_control_cap)); + } /* * Read REPLAY info @@ -2573,7 +2583,7 @@ bool dp_is_sink_present(struct dc_link *link) /* We can't perform the step below for ASICs with no Native * I2C signaling support on DP connectors, so skip it. */ - if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) + if (link->force_to_use_aux) return present; ddc = get_ddc_pin(link->ddc); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c index d87f87a02d63..0d4f88ff844d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_panel_replay.c @@ -25,6 +25,7 @@ #include "link_dp_panel_replay.h" #include "link_edp_panel_control.h" +#include "link_ddc.h" #include "link_dpcd.h" #include "dm_helpers.h" #include "dc/dc_dmub_srv.h" @@ -119,7 +120,7 @@ static bool dp_setup_panel_replay(struct dc_link *link, const struct dc_stream_s if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; - replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; + replay_context.aux_inst = (enum channel_id) link_get_ddc_aux_inst(link); replay_context.digbe_inst = link->link_enc->transmitter; replay_context.digfe_inst = link->link_enc->preferred_engine; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index 80a372ceaa51..baf57692bbb5 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -29,6 +29,7 @@ */ #include "link_edp_panel_control.h" +#include "link_ddc.h" #include "link_dpcd.h" #include "link_dp_capability.h" #include "dm_helpers.h" @@ -788,10 +789,7 @@ bool edp_setup_psr(struct dc_link *link, } } - if (dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) - psr_context->channel = (enum channel_id)link->aux_hw_inst; - else - psr_context->channel = link->ddc->ddc_pin->hw_info.ddc_channel; + psr_context->channel = link_get_ddc_aux_inst(link); psr_context->transmitterId = link->link_enc->transmitter; psr_context->engineId = link->link_enc->preferred_engine; @@ -1024,7 +1022,7 @@ bool edp_setup_freesync_replay(struct dc_link *link, const struct dc_stream_stat if (!dp_pr_get_panel_inst(dc, link, &panel_inst)) return false; - replay_context.aux_inst = link->ddc->ddc_pin->hw_info.ddc_channel; + replay_context.aux_inst = link_get_ddc_aux_inst(link); replay_context.digbe_inst = link->link_enc->transmitter; replay_context.digfe_inst = link->link_enc->preferred_engine; diff --git a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c index fa600593f4c1..0e09d073ab29 100644 --- a/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/mpc/dcn20/dcn20_mpc.c @@ -380,7 +380,6 @@ static void mpc20_program_ogam_pwl( struct dcn20_mpc *mpc20 = TO_DCN20_MPC(mpc); PERF_TRACE(); - REG_SEQ_START(); for (i = 0 ; i < num; i++) { REG_SET(MPCC_OGAM_LUT_DATA[mpcc_id], 0, MPCC_OGAM_LUT_DATA, rgb[i].red_reg); @@ -395,9 +394,6 @@ static void mpc20_program_ogam_pwl( MPCC_OGAM_LUT_DATA, rgb[i].delta_blue_reg); } - REG_SEQ_SUBMIT(); - PERF_TRACE(); - REG_SEQ_WAIT_DONE(); PERF_TRACE(); } diff --git a/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c b/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c index 83730bbe26a8..881b8da656b2 100644 --- a/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c +++ b/drivers/gpu/drm/amd/display/dc/opp/dcn20/dcn20_opp.c @@ -89,6 +89,24 @@ void opp2_set_disp_pattern_generator( break; } + if (opp->ctx->dc->debug.disable_dynamic_expansion_for_test_pattern) { + switch (test_pattern) { + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: + case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: + case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: + case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: + if (color_depth == COLOR_DEPTH_121212) + REG_UPDATE(FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN, 0); + break; + case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: + REG_UPDATE(FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN, 1); + break; + default: + break; + } + } + /* set DPG dimentions */ REG_SET_2(DPG_DIMENSIONS, 0, DPG_ACTIVE_WIDTH, width, @@ -149,6 +167,9 @@ void opp2_set_disp_pattern_generator( case TEST_PATTERN_COLOR_FORMAT_BPC_10: dst_bpc = 10; break; + case TEST_PATTERN_COLOR_FORMAT_BPC_12: + dst_bpc = 12; + break; default: dst_bpc = 8; break; @@ -192,22 +213,25 @@ void opp2_set_disp_pattern_generator( case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: { - mode = (bit_depth == - TEST_PATTERN_COLOR_FORMAT_BPC_10 ? - TEST_PATTERN_MODE_DUALRAMP_RGB : - TEST_PATTERN_MODE_SINGLERAMP_RGB); - switch (bit_depth) { case TEST_PATTERN_COLOR_FORMAT_BPC_6: + mode = TEST_PATTERN_MODE_SINGLERAMP_RGB; dst_bpc = 6; break; case TEST_PATTERN_COLOR_FORMAT_BPC_8: + mode = TEST_PATTERN_MODE_SINGLERAMP_RGB; dst_bpc = 8; break; case TEST_PATTERN_COLOR_FORMAT_BPC_10: + mode = TEST_PATTERN_MODE_DUALRAMP_RGB; dst_bpc = 10; break; + case TEST_PATTERN_COLOR_FORMAT_BPC_12: + mode = TEST_PATTERN_MODE_DUALRAMP_RGB; + dst_bpc = 12; + break; default: + mode = TEST_PATTERN_MODE_SINGLERAMP_RGB; dst_bpc = 8; break; } @@ -244,9 +268,20 @@ void opp2_set_disp_pattern_generator( case TEST_PATTERN_COLOR_FORMAT_BPC_10: { REG_SET_3(DPG_RAMP_CONTROL, 0, - DPG_RAMP0_OFFSET, 384 << 6, - DPG_INC0, inc_base, - DPG_INC1, inc_base + 2); + DPG_RAMP0_OFFSET, 384 << inc_base, // 384 start point + DPG_INC0, inc_base, // step size of 1 + DPG_INC1, inc_base + 2); // step size of 4 (1 << 2) + REG_UPDATE_2(DPG_CONTROL, + DPG_VRES, 5, + DPG_HRES, 8); + } + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_12: + { + REG_SET_3(DPG_RAMP_CONTROL, 0, + DPG_RAMP0_OFFSET, 1920 << inc_base, // 1920 start point + DPG_INC0, inc_base, // step size of 1 + DPG_INC1, inc_base + 4); // step size of 16 (1 << 4) REG_UPDATE_2(DPG_CONTROL, DPG_VRES, 5, DPG_HRES, 8); diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c index e6426ccee2d8..cf8e22289d6a 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c @@ -539,16 +539,11 @@ static bool optc1_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); - REG_SEQ_START(); - /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 3, OTG_MASTER_EN, 1); - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c index c558b1d633f3..73cc8a713556 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c @@ -63,16 +63,11 @@ bool optc2_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); - REG_SEQ_START(); - /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 3, OTG_MASTER_EN, 1); - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c index 98aaa22ce81c..3ace83e1b50f 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c @@ -105,16 +105,11 @@ static bool optc31_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); - REG_SEQ_START(); - /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 2, OTG_MASTER_EN, 1); - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c index a7cf34937b2f..7250478a5092 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c @@ -115,16 +115,11 @@ static bool optc314_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); - REG_SEQ_START(); - /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 2, OTG_MASTER_EN, 1); - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c index 07895d5f4dfa..f9e05efcad98 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c @@ -155,16 +155,11 @@ static bool optc32_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); - REG_SEQ_START(); - /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 2, OTG_MASTER_EN, 1); - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c index 62f45c156c32..9b7f9d5bbfb3 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c @@ -122,16 +122,11 @@ static bool optc35_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); - REG_SEQ_START(); - /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 2, OTG_MASTER_EN, 1); - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c index a6d76f451cf8..5fcdd74eb4a0 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c @@ -189,16 +189,11 @@ bool optc401_enable_crtc(struct timing_generator *optc) REG_UPDATE(CONTROL, VTG0_ENABLE, 1); - REG_SEQ_START(); - /* Enable CRTC */ REG_UPDATE_2(OTG_CONTROL, OTG_DISABLE_POINT_CNTL, 2, OTG_MASTER_EN, 1); - REG_SEQ_SUBMIT(); - REG_SEQ_WAIT_DONE(); - return true; } diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c index 729c2b653161..78b33b2dbae8 100644 --- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c +++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.c @@ -22,6 +22,60 @@ #define DC_LOGGER \ pg_cntl->ctx->logger +/* + * ONO PG Workoaround: Saved FGCG repeaters states captured before powering up an ONO + * domain so it can be restored once the domain is powered up. + */ +struct dcn42_global_fgcg_rep_state { + uint32_t dmu_rep_fgcg; + uint32_t dccg_global_ono_rep_fgcg; + uint32_t az_rep_fgcg; +}; + +/* Save and disable FGCG repeaters before powering up the ONO domain. */ +static void pg_cntl42_save_and_disable_global_fgcg_rep(struct pg_cntl *pg_cntl, + struct dcn42_global_fgcg_rep_state *state) +{ + struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); + + REG_GET(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, &state->dmu_rep_fgcg); + if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_get_global_fgcg_status) + state->dccg_global_ono_rep_fgcg = pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_get_global_fgcg_status(pg_cntl->ctx->dc->res_pool->dccg); + REG_GET(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, &state->az_rep_fgcg); + + REG_UPDATE(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, 1); + if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) + pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); + REG_UPDATE(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, 1); +} + +/* Restore FGCG repeaters after the ONO domains are powered up. */ +static void pg_cntl42_restore_global_fgcg_rep(struct pg_cntl *pg_cntl, + struct dcn42_global_fgcg_rep_state *state) +{ + struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); + + REG_UPDATE(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, state->dmu_rep_fgcg); + if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) + pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, state->dccg_global_ono_rep_fgcg); + REG_UPDATE(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, state->az_rep_fgcg); +} + +static bool should_skip_pg_control(bool dc_in_idle_opt, bool power_on, bool block_enabled) +{ + if (dc_in_idle_opt) + return true; + + if (power_on && block_enabled) + return true; + + if (!power_on && !block_enabled) + return true; + + return false; +} + + static bool pg_cntl42_dsc_pg_status(struct pg_cntl *pg_cntl, unsigned int dsc_inst) { struct dcn_pg_cntl *pg_cntl_dcn = TO_DCN_PG_CNTL(pg_cntl); @@ -54,37 +108,23 @@ void pg_cntl42_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl = 0; - bool block_enabled; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; + bool block_pg_disabled = pg_cntl->ctx->dc->debug.ignore_pg || pg_cntl->ctx->dc->debug.disable_dsc_power_gate; - /*need to enable dscclk regardless DSC_PG*/ - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc && power_on) - pg_cntl->ctx->dc->res_pool->dccg->funcs->enable_dsc( - pg_cntl->ctx->dc->res_pool->dccg, dsc_inst); - - bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->debug.disable_dsc_power_gate || - pg_cntl->ctx->dc->idle_optimizations_allowed; - - if (skip_pg && !power_on) + if (block_pg_disabled && !power_on) return; - block_enabled = pg_cntl42_dsc_pg_status(pg_cntl, dsc_inst); - if (power_on) { - if (block_enabled) - return; - } else { - if (!block_enabled) - return; - } + bool block_enabled = pg_cntl42_dsc_pg_status(pg_cntl, dsc_inst); + if (should_skip_pg_control(pg_cntl->ctx->dc->idle_optimizations_allowed, power_on, block_enabled)) + return; REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + switch (dsc_inst) { case 0: /* DSC0 */ REG_UPDATE(DOMAIN16_PG_CONFIG, @@ -123,19 +163,11 @@ void pg_cntl42_dsc_pg_control(struct pg_cntl *pg_cntl, unsigned int dsc_inst, bo break; } - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); if (dsc_inst < MAX_PIPES) pg_cntl->pg_pipe_res_enable[PG_DSC][dsc_inst] = power_on; - - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc && !power_on) { - /*this is to disable dscclk*/ - pg_cntl->ctx->dc->res_pool->dccg->funcs->disable_dsc( - pg_cntl->ctx->dc->res_pool->dccg, dsc_inst); - } } static bool pg_cntl42_hubp_dpp_pg_status(struct pg_cntl *pg_cntl, unsigned int hubp_dpp_inst) @@ -174,32 +206,24 @@ void pg_cntl42_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; - bool block_enabled; - bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->debug.disable_hubp_power_gate || - pg_cntl->ctx->dc->debug.disable_dpp_power_gate || - pg_cntl->ctx->dc->idle_optimizations_allowed; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; + bool block_pg_disabled = pg_cntl->ctx->dc->debug.ignore_pg || + pg_cntl->ctx->dc->debug.disable_hubp_power_gate || + pg_cntl->ctx->dc->debug.disable_dpp_power_gate; - if (skip_pg && !power_on) + if (block_pg_disabled && !power_on) return; - block_enabled = pg_cntl42_hubp_dpp_pg_status(pg_cntl, hubp_dpp_inst); - if (power_on) { - if (block_enabled) - return; - } else { - if (!block_enabled) - return; - } + bool block_enabled = pg_cntl42_hubp_dpp_pg_status(pg_cntl, hubp_dpp_inst); + if (should_skip_pg_control(pg_cntl->ctx->dc->idle_optimizations_allowed, power_on, block_enabled)) + return; REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); switch (hubp_dpp_inst) { case 0: @@ -227,10 +251,9 @@ void pg_cntl42_hubp_dpp_pg_control(struct pg_cntl *pg_cntl, unsigned int hubp_dp break; } - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + DC_LOG_DEBUG("HUBP DPP instance %d, power %s", hubp_dpp_inst, power_on ? "ON" : "OFF"); @@ -258,22 +281,18 @@ void pg_cntl42_hpo_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; uint32_t power_forceon; - bool block_enabled; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; - bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->debug.disable_hpo_power_gate || - pg_cntl->ctx->dc->idle_optimizations_allowed; + bool block_pg_disabled = pg_cntl->ctx->dc->debug.ignore_pg || + pg_cntl->ctx->dc->debug.disable_hpo_power_gate; - if (skip_pg && !power_on) + if (block_pg_disabled && !power_on) + return; + + bool block_enabled = pg_cntl42_hpo_pg_status(pg_cntl); + + if (should_skip_pg_control(pg_cntl->ctx->dc->idle_optimizations_allowed, power_on, block_enabled)) return; - block_enabled = pg_cntl42_hpo_pg_status(pg_cntl); - if (power_on) { - if (block_enabled) - return; - } else { - if (!block_enabled) - return; - } REG_GET(DOMAIN25_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); if (power_forceon) @@ -282,17 +301,15 @@ void pg_cntl42_hpo_pg_control(struct pg_cntl *pg_cntl, bool power_on) REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + REG_UPDATE(DOMAIN25_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); REG_WAIT(DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + pg_cntl->pg_res_enable[PG_HPO] = power_on; } @@ -314,23 +331,17 @@ void pg_cntl42_io_clk_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; uint32_t power_forceon; - bool block_enabled; - bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->idle_optimizations_allowed || + bool block_pg_disabled = pg_cntl->ctx->dc->debug.ignore_pg || pg_cntl->ctx->dc->debug.disable_io_clk_power_gate; - if (skip_pg && !power_on) + if (block_pg_disabled && !power_on) return; - block_enabled = pg_cntl42_io_clk_status(pg_cntl); - if (power_on) { - if (block_enabled) - return; - } else { - if (!block_enabled) - return; - } + bool block_enabled = pg_cntl42_io_clk_status(pg_cntl); + + if (should_skip_pg_control(pg_cntl->ctx->dc->idle_optimizations_allowed, power_on, block_enabled)) + return; REG_GET(DOMAIN22_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); if (power_forceon) @@ -412,24 +423,16 @@ void pg_cntl42_mem_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; uint32_t power_forceon; - bool block_enabled; - bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->idle_optimizations_allowed || + bool block_pg_disabled = pg_cntl->ctx->dc->debug.ignore_pg || pg_cntl->ctx->dc->debug.disable_mem_power_gate; - if (skip_pg && !power_on) + if (block_pg_disabled && !power_on) return; - block_enabled = pg_cntl42_mem_status(pg_cntl); - if (power_on) { - if (block_enabled) - return; - } else { - if (!block_enabled) - return; - } - + bool block_enabled = pg_cntl42_mem_status(pg_cntl); + if (should_skip_pg_control(pg_cntl->ctx->dc->idle_optimizations_allowed, power_on, block_enabled)) + return; REG_GET(DOMAIN23_PG_CONFIG, DOMAIN_POWER_FORCEON, &power_forceon); if (power_forceon) return; @@ -466,38 +469,31 @@ void pg_cntl42_dio_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t power_gate = power_on ? 0 : 1; uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; - bool block_enabled; + struct dcn42_global_fgcg_rep_state fgcg_rep_state = {0}; - bool skip_pg = pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->idle_optimizations_allowed || + bool block_pg_disabled = pg_cntl->ctx->dc->debug.ignore_pg || pg_cntl->ctx->dc->debug.disable_dio_power_gate; - if (skip_pg && !power_on) + + if (block_pg_disabled && !power_on) return; - block_enabled = pg_cntl42_dio_pg_status(pg_cntl); - if (power_on) { - if (block_enabled) - return; - } else { - if (!block_enabled) - return; - } + bool block_enabled = pg_cntl42_dio_pg_status(pg_cntl); + if (should_skip_pg_control(pg_cntl->ctx->dc->idle_optimizations_allowed, power_on, block_enabled)) + return; REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl); if (org_ip_request_cntl == 0) REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, false); - } + if (power_on) + pg_cntl42_save_and_disable_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + /* DIO */ REG_UPDATE(DOMAIN26_PG_CONFIG, DOMAIN_POWER_GATE, power_gate); REG_WAIT(DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, pwr_status, 1, 1000); - if (power_on) { - if (pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg) - pg_cntl->ctx->dc->res_pool->dccg->funcs->dccg_enable_global_fgcg(pg_cntl->ctx->dc->res_pool->dccg, true); - } + if (power_on) + pg_cntl42_restore_global_fgcg_rep(pg_cntl, &fgcg_rep_state); + pg_cntl->pg_res_enable[PG_DIO] = power_on; } @@ -509,23 +505,19 @@ void pg_cntl42_plane_otg_pg_control(struct pg_cntl *pg_cntl, bool power_on) uint32_t pwr_status = power_on ? 0 : 2; uint32_t org_ip_request_cntl; unsigned int i; - bool block_enabled; bool all_mpcc_disabled = true, all_opp_disabled = true; bool all_optc_disabled = true, all_stream_disabled = true; - if (pg_cntl->ctx->dc->debug.ignore_pg || - pg_cntl->ctx->dc->debug.disable_optc_power_gate || - pg_cntl->ctx->dc->idle_optimizations_allowed) + bool block_pg_disabled = pg_cntl->ctx->dc->debug.ignore_pg || + pg_cntl->ctx->dc->debug.disable_optc_power_gate; + + if (block_pg_disabled && !power_on) return; - block_enabled = pg_cntl42_plane_otg_status(pg_cntl); - if (power_on) { - if (block_enabled) - return; - } else { - if (!block_enabled) - return; - } + bool block_enabled = pg_cntl42_plane_otg_status(pg_cntl); + + if (should_skip_pg_control(pg_cntl->ctx->dc->idle_optimizations_allowed, power_on, block_enabled)) + return; for (i = 0; i < pg_cntl->ctx->dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe_ctx = &pg_cntl->ctx->dc->current_state->res_ctx.pipe_ctx[i]; diff --git a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h index 7e8f4f03ae0e..813fa5c81172 100644 --- a/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h +++ b/drivers/gpu/drm/amd/display/dc/pg/dcn42/dcn42_pg_cntl.h @@ -34,7 +34,9 @@ SR(DOMAIN24_PG_STATUS), \ SR(DOMAIN25_PG_STATUS), \ SR(DOMAIN26_PG_STATUS), \ - SR(DC_IP_REQUEST_CNTL) + SR(DC_IP_REQUEST_CNTL), \ + SR(DMU_CLK_CNTL), \ + SR(AZ_CLOCK_CNTL) #define PG_CNTL_REG_LIST_DCN42B()\ SR(DOMAIN0_PG_CONFIG), \ @@ -63,7 +65,9 @@ SR(DOMAIN24_PG_STATUS), \ SR(DOMAIN25_PG_STATUS), \ SR(DOMAIN26_PG_STATUS), \ - SR(DC_IP_REQUEST_CNTL) + SR(DC_IP_REQUEST_CNTL), \ + SR(DMU_CLK_CNTL), \ + SR(AZ_CLOCK_CNTL) #define PG_CNTL_SF(reg_name, field_name, post_fix)\ .field_name = reg_name ## __ ## field_name ## post_fix @@ -121,7 +125,9 @@ PG_CNTL_SF(DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_DESIRED_PWR_STATE, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) + PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + PG_CNTL_SF(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, mask_sh), \ + PG_CNTL_SF(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, mask_sh) /* Not in DCN42B: * PG_CNTL_SF(DOMAIN19_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), @@ -178,7 +184,9 @@ PG_CNTL_SF(DOMAIN25_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_DESIRED_PWR_STATE, mask_sh), \ PG_CNTL_SF(DOMAIN26_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \ - PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh) + PG_CNTL_SF(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \ + PG_CNTL_SF(DMU_CLK_CNTL, LONO_FGCG_REP_DIS, mask_sh), \ + PG_CNTL_SF(AZ_CLOCK_CNTL, AZ_GLOBAL_FGCG_REP_DIS, mask_sh) struct pg_cntl_shift { uint8_t IP_REQUEST_EN; @@ -186,6 +194,8 @@ struct pg_cntl_shift { uint8_t DOMAIN_POWER_GATE; uint8_t DOMAIN_DESIRED_PWR_STATE; uint8_t DOMAIN_PGFSM_PWR_STATUS; + uint8_t LONO_FGCG_REP_DIS; + uint8_t AZ_GLOBAL_FGCG_REP_DIS; }; struct pg_cntl_mask { uint32_t IP_REQUEST_EN; @@ -193,6 +203,8 @@ struct pg_cntl_mask { uint32_t DOMAIN_POWER_GATE; uint32_t DOMAIN_DESIRED_PWR_STATE; uint32_t DOMAIN_PGFSM_PWR_STATUS; + uint32_t LONO_FGCG_REP_DIS; + uint32_t AZ_GLOBAL_FGCG_REP_DIS; }; struct pg_cntl_registers { @@ -224,6 +236,8 @@ struct pg_cntl_registers { uint32_t DOMAIN24_PG_STATUS; uint32_t DOMAIN25_PG_STATUS; uint32_t DOMAIN26_PG_STATUS; + uint32_t DMU_CLK_CNTL; + uint32_t AZ_CLOCK_CNTL; }; struct dcn_pg_cntl { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 01770df63d0e..d11ab57afcdd 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -2479,7 +2479,6 @@ static bool dcn30_resource_construct( dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c index 58add1071bc1..ae8918a4ad3e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c @@ -1378,7 +1378,6 @@ static bool dcn302_resource_construct( dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; dc->caps.max_v_total = (1 << 15) - 1; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c index 6cb297cd08fd..75e6f4e46f60 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c @@ -1322,7 +1322,6 @@ static bool dcn303_resource_construct( dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.extended_aux_timeout_support = true; dc->caps.dmcub_support = true; dc->caps.max_v_total = (1 << 15) - 1; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 7c6a6872688b..e29efa452c87 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -1189,7 +1189,7 @@ static struct link_encoder *dcn31_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if (((unsigned int)eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if (((unsigned int)eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1201,6 +1201,8 @@ static struct link_encoder *dcn31_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; @@ -2077,7 +2079,6 @@ static bool dcn31_resource_construct( if (dc->config.forceHBR2CP2520) dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c index d8096f11fb77..f50b3250dcba 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c @@ -1246,7 +1246,7 @@ static struct link_encoder *dcn31_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if (((unsigned int)eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if (((unsigned int)eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1258,6 +1258,8 @@ static struct link_encoder *dcn31_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index 3b2e57c6970f..8297f2f04c16 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -1188,7 +1188,7 @@ static struct link_encoder *dcn31_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if (((unsigned int)eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if (((unsigned int)eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1200,6 +1200,8 @@ static struct link_encoder *dcn31_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; @@ -2053,7 +2055,6 @@ static bool dcn315_resource_construct( if (dc->config.forceHBR2CP2520) dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c index 924b167bcd74..046566ad1afe 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c @@ -1181,7 +1181,7 @@ static struct link_encoder *dcn31_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if (((unsigned int)eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if (((unsigned int)eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1193,6 +1193,8 @@ static struct link_encoder *dcn31_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; @@ -1927,7 +1929,6 @@ static bool dcn316_resource_construct( if (dc->config.forceHBR2CP2520) dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index a11110e304fc..004c5690f876 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -2405,7 +2405,6 @@ static bool dcn32_resource_construct( if (dc->config.forceHBR2CP2520) dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index d1dbcc8ddb71..53fd32249310 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -1897,7 +1897,6 @@ static bool dcn321_resource_construct( dc->caps.post_blend_color_processing = true; dc->caps.force_dp_tps4_for_cp2520 = true; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; dc->caps.edp_dsc_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 53596e790eb4..5541b89b1350 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -819,7 +819,6 @@ static const struct dc_debug_options debug_defaults_drv = { .enable_hpo_pg_support = false, .enable_single_display_2to1_odm_policy = true, .disable_idle_power_optimizations = false, - .dmcub_emulation = false, .disable_boot_optimizations = false, .disable_unbounded_requesting = false, .disable_mem_low_power = false, @@ -1189,7 +1188,7 @@ static struct link_encoder *dcn31_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if (((unsigned int)eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if (((unsigned int)eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1201,6 +1200,8 @@ static struct link_encoder *dcn31_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; @@ -2029,7 +2030,6 @@ static bool dcn35_resource_construct( if (dc->config.forceHBR2CP2520) dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c index 3e2c9cfd555d..053b4380f57e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c @@ -799,7 +799,6 @@ static const struct dc_debug_options debug_defaults_drv = { .enable_hpo_pg_support = false, .enable_single_display_2to1_odm_policy = true, .disable_idle_power_optimizations = false, - .dmcub_emulation = false, .disable_boot_optimizations = false, .disable_unbounded_requesting = false, .disable_mem_low_power = false, @@ -1169,7 +1168,7 @@ static struct link_encoder *dcn31_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if (((unsigned int)eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if (((unsigned int)eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1181,6 +1180,8 @@ static struct link_encoder *dcn31_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; @@ -2002,7 +2003,6 @@ static bool dcn351_resource_construct( if (dc->config.forceHBR2CP2520) dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c index 9e795130eb89..592000cf9250 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c @@ -806,7 +806,6 @@ static const struct dc_debug_options debug_defaults_drv = { .enable_hpo_pg_support = false, .enable_single_display_2to1_odm_policy = true, .disable_idle_power_optimizations = false, - .dmcub_emulation = false, .disable_boot_optimizations = false, .disable_unbounded_requesting = false, .disable_mem_low_power = false, @@ -1176,7 +1175,7 @@ static struct link_encoder *dcn31_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if (((unsigned int)eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if (((unsigned int)eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc_obj(struct dcn20_link_encoder); @@ -1188,6 +1187,8 @@ static struct link_encoder *dcn31_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; @@ -1999,7 +2000,6 @@ static bool dcn36_resource_construct( if (dc->config.forceHBR2CP2520) dc->caps.force_dp_tps4_for_cp2520 = false; dc->caps.hdmi_hpo = true; - dc->config.skip_frl_pretraining = true; dc->caps.dp_hpo = true; dc->caps.dp_hdmi21_pcon_support = true; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c index 7de12b16d7ad..7620da96ffc1 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42/dcn42_resource.c @@ -801,6 +801,7 @@ static const struct dc_debug_options debug_defaults_drv = { .replay_skip_crtc_disabled = true, .psr_skip_crtc_disable = true, .force_odm2to1_for_edp_pixclk_mhz = 0, // disable the policy for now + .iommu_mismatch_temp_wka = 0x7, }; static const struct dc_check_config config_defaults = { @@ -1881,7 +1882,7 @@ static struct link_encoder *dcn42_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if ((unsigned int)(eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if ((unsigned int)(eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); @@ -1893,6 +1894,8 @@ static struct link_encoder *dcn42_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c index 527d17f29f3b..60cbaf4f6fdf 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn42b/dcn42b_resource.c @@ -757,7 +757,7 @@ static const struct dc_debug_options debug_defaults_drv = { .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, - .pstate_enabled = false, + .pstate_enabled = true, .enable_mem_low_power = { .bits = { .vga = false, @@ -1824,7 +1824,7 @@ static struct link_encoder *dcn42b_link_enc_create_minimal( { struct dcn20_link_encoder *enc20; - if ((unsigned int)(eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc) + if ((unsigned int)(eng_id - ENGINE_ID_DIGA) >= ctx->dc->res_pool->res_cap->num_dig_link_enc) return NULL; enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL); @@ -1836,6 +1836,8 @@ static struct link_encoder *dcn42b_link_enc_create_minimal( ctx, &link_enc_feature, &link_enc_regs[eng_id - ENGINE_ID_DIGA], + &le_shift, + &le_mask, eng_id); return &enc20->enc10.base; diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/Makefile b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/Makefile index d168fb1eacf7..8a9bb0aef9b7 100644 --- a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/Makefile +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/Makefile @@ -9,13 +9,16 @@ soc_and_ip_translator_rcflags := $(CC_FLAGS_NO_FPU) CFLAGS_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.o := $(soc_and_ip_translator_ccflags) CFLAGS_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.o := $(soc_and_ip_translator_ccflags) +CFLAGS_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.o := $(soc_and_ip_translator_ccflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.o := $(soc_and_ip_translator_rcflags) CFLAGS_REMOVE_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.o := $(soc_and_ip_translator_rcflags) +CFLAGS_REMOVE_$(AMDDALPATH)/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.o := $(soc_and_ip_translator_rcflags) soc_and_ip_translator := soc_and_ip_translator.o soc_and_ip_translator += dcn401/dcn401_soc_and_ip_translator.o soc_and_ip_translator += dcn42/dcn42_soc_and_ip_translator.o +soc_and_ip_translator += dcn42b/dcn42b_soc_and_ip_translator.o AMD_DAL_soc_and_ip_translator := $(addprefix $(AMDDALPATH)/dc/soc_and_ip_translator/, $(soc_and_ip_translator)) diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c index ae2c6a2f3f75..c6c1b19b7370 100644 --- a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.c @@ -5,22 +5,16 @@ #include "dcn42_soc_and_ip_translator.h" #include "../dcn401/dcn401_soc_and_ip_translator.h" #include "bounding_boxes/dcn42_soc_bb.h" -#include "bounding_boxes/dcn42b_soc_bb.h" /* soc_and_ip_translator component used to get up-to-date values for bounding box. * Bounding box values are stored in several locations and locations can vary with DCN revision. * This component provides an interface to get DCN-specific bounding box values. */ -static void get_default_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc) +static void get_default_soc_bb(struct dml2_soc_bb *soc_bb) { - if (dc->ctx->dce_version == DCN_VERSION_4_2B) { - memcpy(soc_bb, &dml2_socbb_dcn42b, sizeof(struct dml2_soc_bb)); - memcpy(&soc_bb->qos_parameters, &dml_dcn42b_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters)); - } else { - memcpy(soc_bb, &dml2_socbb_dcn42, sizeof(struct dml2_soc_bb)); - memcpy(&soc_bb->qos_parameters, &dml_dcn42_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters)); - } + memcpy(soc_bb, &dml2_socbb_dcn42, sizeof(struct dml2_soc_bb)); + memcpy(&soc_bb->qos_parameters, &dml_dcn42_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters)); } /* @@ -165,7 +159,7 @@ static void dcn42_update_soc_bb_with_values_from_clk_mgr(struct dml2_soc_bb *soc } } -static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) +void dcn42_apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) { (void)config; /* Individual modification can be overwritten even if it was obtained by a previous function. @@ -181,9 +175,9 @@ static void apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc void dcn42_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) { //get default soc_bb with static values - get_default_soc_bb(soc_bb, dc); + get_default_soc_bb(soc_bb); //update soc_bb values with more accurate values - apply_soc_bb_updates(soc_bb, dc, config); + dcn42_apply_soc_bb_updates(soc_bb, dc, config); } static void dcn42_get_ip_caps(struct dml2_ip_capabilities *ip_caps) diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h index 1dded5426152..8ac90655f276 100644 --- a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h @@ -13,5 +13,6 @@ void dcn42_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator); void dcn42_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config); +void dcn42_apply_soc_bb_updates(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config); #endif /* _DCN42_SOC_AND_IP_TRANSLATOR_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.c new file mode 100644 index 000000000000..50669f458e23 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2026 Advanced Micro Devices, Inc. + +#include "../dcn42/dcn42_soc_and_ip_translator.h" +#include "dcn42b_soc_and_ip_translator.h" +#include "../dcn401/dcn401_soc_and_ip_translator.h" +#include "bounding_boxes/dcn42b_soc_bb.h" + +/* soc_and_ip_translator component used to get up-to-date values for bounding box. + * Bounding box values are stored in several locations and locations can vary with DCN revision. + * This component provides an interface to get DCN-specific bounding box values. + */ + +static void get_default_soc_bb(struct dml2_soc_bb *soc_bb) +{ + memcpy(soc_bb, &dml2_socbb_dcn42b, sizeof(struct dml2_soc_bb)); + memcpy(&soc_bb->qos_parameters, &dml_dcn42b_variant_a_soc_qos_params, sizeof(struct dml2_soc_qos_parameters)); +} + +void dcn42b_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config) +{ + //get default soc_bb with static values + get_default_soc_bb(soc_bb); + //update soc_bb values with more accurate values + dcn42_apply_soc_bb_updates(soc_bb, dc, config); +} + +static void dcn42b_get_ip_caps(struct dml2_ip_capabilities *ip_caps) +{ + *ip_caps = dml2_dcn42b_max_ip_caps; +} + +static struct soc_and_ip_translator_funcs dcn42b_translator_funcs = { + .get_soc_bb = dcn42b_get_soc_bb, + .get_ip_caps = dcn42b_get_ip_caps, +}; + +void dcn42b_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator) +{ + soc_and_ip_translator->translator_funcs = &dcn42b_translator_funcs; +} diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.h b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.h new file mode 100644 index 000000000000..0d4ea613431a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +// +// Copyright 2026 Advanced Micro Devices, Inc. + +#ifndef _DCN42B_SOC_AND_IP_TRANSLATOR_H_ +#define _DCN42B_SOC_AND_IP_TRANSLATOR_H_ + +#include "core_types.h" +#include "dc.h" +#include "clk_mgr.h" +#include "dml_top_soc_parameter_types.h" +#include "soc_and_ip_translator.h" + +void dcn42b_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator); +void dcn42b_get_soc_bb(struct dml2_soc_bb *soc_bb, const struct dc *dc, const struct dml2_configuration_options *config); + +#endif /* _DCN42B_SOC_AND_IP_TRANSLATOR_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/soc_and_ip_translator.c b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/soc_and_ip_translator.c index f99afb22d7da..1e3ee25732fa 100644 --- a/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/soc_and_ip_translator.c +++ b/drivers/gpu/drm/amd/display/dc/soc_and_ip_translator/soc_and_ip_translator.c @@ -5,6 +5,7 @@ #include "soc_and_ip_translator.h" #include "soc_and_ip_translator/dcn401/dcn401_soc_and_ip_translator.h" #include "soc_and_ip_translator/dcn42/dcn42_soc_and_ip_translator.h" +#include "soc_and_ip_translator/dcn42b/dcn42b_soc_and_ip_translator.h" static void dc_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc_and_ip_translator, enum dce_version dc_version) @@ -14,9 +15,11 @@ static void dc_construct_soc_and_ip_translator(struct soc_and_ip_translator *soc dcn401_construct_soc_and_ip_translator(soc_and_ip_translator); break; case DCN_VERSION_4_2: - case DCN_VERSION_4_2B: dcn42_construct_soc_and_ip_translator(soc_and_ip_translator); break; + case DCN_VERSION_4_2B: + dcn42b_construct_soc_and_ip_translator(soc_and_ip_translator); + break; default: break; } diff --git a/drivers/gpu/drm/amd/display/dc/sspl/spl_debug.h b/drivers/gpu/drm/amd/display/dc/sspl/spl_debug.h index a6f6132df241..a0e9df382582 100644 --- a/drivers/gpu/drm/amd/display/dc/sspl/spl_debug.h +++ b/drivers/gpu/drm/amd/display/dc/sspl/spl_debug.h @@ -5,7 +5,7 @@ #ifndef SPL_DEBUG_H #define SPL_DEBUG_H -#if defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB) +#ifdef CONFIG_KGDB #define SPL_ASSERT_CRITICAL(expr) do { \ if (WARN_ON(!(expr))) { \ kgdb_breakpoint(); \ @@ -17,7 +17,7 @@ ; \ } \ } while (0) -#endif /* CONFIG_HAVE_KGDB || CONFIG_KGDB */ +#endif /* CONFIG_KGDB */ #if defined(CONFIG_DEBUG_KERNEL_DC) #define SPL_ASSERT(expr) SPL_ASSERT_CRITICAL(expr) diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 6f6a59a23495..e7879bd81f83 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -246,14 +246,14 @@ * OS/FW agnostic memcpy */ #ifndef dmub_memcpy -#define dmub_memcpy(dest, source, bytes) memcpy((dest), (source), (bytes)) +#define dmub_memcpy(dest, source, bytes) ((void)memcpy((dest), (source), (bytes))) #endif /** * OS/FW agnostic memset */ #ifndef dmub_memset -#define dmub_memset(dest, val, bytes) memset((dest), (val), (bytes)) +#define dmub_memset(dest, val, bytes) ((void)memset((dest), (val), (bytes))) #endif /** @@ -1702,6 +1702,17 @@ enum dmub_gpint_command { * ARGS: 1 - Power off */ DMUB_GPINT__PANEL_POWER_OFF_SEQ = 138, + /** + * DESC: Gets panel polarity bias. + * ARGS: 0 - Get panel polarity bias + */ + DMUB_GPINT__PANEL_POLARITY_GET_BIAS = 139, + /** + * DESC: Enables panel polarity. + * ARGS: 0 - Disable panel polarity + * 1 - Enable panel polarity + */ + DMUB_GPINT__PANEL_POLARITY_DEBUG_ENABLE = 140, }; /** @@ -1800,28 +1811,13 @@ enum dmub_inbox0_command { * * Command IDs should be treated as stable ABI. * Do not reuse or modify IDs. + * Note that command IDs 1-4 have been deprecated. */ enum dmub_cmd_type { /** * Invalid command. */ DMUB_CMD__NULL = 0, - /** - * Read modify write register sequence offload. - */ - DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE = 1, - /** - * Field update register sequence offload. - */ - DMUB_CMD__REG_SEQ_FIELD_UPDATE_SEQ = 2, - /** - * Burst write sequence offload. - */ - DMUB_CMD__REG_SEQ_BURST_WRITE = 3, - /** - * Reg wait sequence offload. - */ - DMUB_CMD__REG_REG_WAIT = 4, /** * Workaround to avoid HUBP underflow during NV12 playback. */ @@ -1971,6 +1967,11 @@ enum dmub_cmd_type { */ DMUB_CMD__BOOT_TIME_CRC = 96, + /** + * Command type use for all Panel Polarity commands. + */ + DMUB_CMD__PANEL_POLARITY = 97, + /** * Command type use for VBIOS shared commands. */ @@ -2041,98 +2042,6 @@ struct dmub_cmd_header { unsigned int reserved1 : 2; /**< reserved bits */ }; -/* - * struct dmub_cmd_read_modify_write_sequence - Read modify write - * - * 60 payload bytes can hold up to 5 sets of read modify writes, - * each take 3 dwords. - * - * number of sequences = header.payload_bytes / sizeof(struct dmub_cmd_read_modify_write_sequence) - * - * modify_mask = 0xffff'ffff means all fields are going to be updated. in this case - * command parser will skip the read and we can use modify_mask = 0xffff'ffff as reg write - */ -struct dmub_cmd_read_modify_write_sequence { - uint32_t addr; /**< register address */ - uint32_t modify_mask; /**< modify mask */ - uint32_t modify_value; /**< modify value */ -}; - -/** - * Maximum number of ops in read modify write sequence. - */ -#define DMUB_READ_MODIFY_WRITE_SEQ__MAX 5 - -/** - * struct dmub_cmd_read_modify_write_sequence - Read modify write command. - */ -struct dmub_rb_cmd_read_modify_write { - struct dmub_cmd_header header; /**< command header */ - /** - * Read modify write sequence. - */ - struct dmub_cmd_read_modify_write_sequence seq[DMUB_READ_MODIFY_WRITE_SEQ__MAX]; -}; - -/* - * Update a register with specified masks and values sequeunce - * - * 60 payload bytes can hold address + up to 7 sets of mask/value combo, each take 2 dword - * - * number of field update sequence = (header.payload_bytes - sizeof(addr)) / sizeof(struct read_modify_write_sequence) - * - * - * USE CASE: - * 1. auto-increment register where additional read would update pointer and produce wrong result - * 2. toggle a bit without read in the middle - */ - -struct dmub_cmd_reg_field_update_sequence { - uint32_t modify_mask; /**< 0xffff'ffff to skip initial read */ - uint32_t modify_value; /**< value to update with */ -}; - -/** - * Maximum number of ops in field update sequence. - */ -#define DMUB_REG_FIELD_UPDATE_SEQ__MAX 7 - -/** - * struct dmub_rb_cmd_reg_field_update_sequence - Field update command. - */ -struct dmub_rb_cmd_reg_field_update_sequence { - struct dmub_cmd_header header; /**< command header */ - uint32_t addr; /**< register address */ - /** - * Field update sequence. - */ - struct dmub_cmd_reg_field_update_sequence seq[DMUB_REG_FIELD_UPDATE_SEQ__MAX]; -}; - - -/** - * Maximum number of burst write values. - */ -#define DMUB_BURST_WRITE_VALUES__MAX 14 - -/* - * struct dmub_rb_cmd_burst_write - Burst write - * - * support use case such as writing out LUTs. - * - * 60 payload bytes can hold up to 14 values to write to given address - * - * number of payload = header.payload_bytes / sizeof(struct read_modify_write_sequence) - */ -struct dmub_rb_cmd_burst_write { - struct dmub_cmd_header header; /**< command header */ - uint32_t addr; /**< register start address */ - /** - * Burst write register values. - */ - uint32_t write_values[DMUB_BURST_WRITE_VALUES__MAX]; -}; - /** * struct dmub_rb_cmd_common - Common command header */ @@ -2144,24 +2053,6 @@ struct dmub_rb_cmd_common { uint8_t cmd_buffer[DMUB_RB_CMD_SIZE - sizeof(struct dmub_cmd_header)]; }; -/** - * struct dmub_cmd_reg_wait_data - Register wait data - */ -struct dmub_cmd_reg_wait_data { - uint32_t addr; /**< Register address */ - uint32_t mask; /**< Mask for register bits */ - uint32_t condition_field_value; /**< Value to wait for */ - uint32_t time_out_us; /**< Time out for reg wait in microseconds */ -}; - -/** - * struct dmub_rb_cmd_reg_wait - Register wait command - */ -struct dmub_rb_cmd_reg_wait { - struct dmub_cmd_header header; /**< Command header */ - struct dmub_cmd_reg_wait_data reg_wait; /**< Register wait data */ -}; - /** * struct dmub_cmd_PLAT_54186_wa - Underflow workaround * @@ -4490,6 +4381,15 @@ enum dmub_cmd_replay_type { DMUB_CMD__REPLAY_SET_GENERAL_CMD = 16, }; +/* + * Panel Polarity sub-types + */ +enum dmub_cmd_panel_polarity_type { + DMUB_CMD__PANEL_POLARITY_ENABLE = 0, + DMUB_CMD__PANEL_POLARITY_GET_BIAS = 1, + DMUB_CMD__PANEL_POLARITY_RESET = 2, +}; + /* * Panel Replay sub-types */ @@ -6439,10 +6339,43 @@ struct dmub_cmd_cacp_set_backlight_data { */ uint8_t panel_mask; + /** + * AUX HW Instance. + */ + uint8_t aux_inst; + /** * Explicit padding to 4 byte boundary. */ - uint8_t pad[2]; + uint8_t pad[1]; + + /** + * Backlight control type. + * Value 0 is PWM backlight control. + * Value 1 is VAUX backlight control. + * Value 2 is AMD DPCD AUX backlight control. + */ + enum dmub_backlight_control_type backlight_control_type; + + /** + * Minimum luminance in nits. + */ + uint32_t min_luminance; + + /** + * Maximum luminance in nits. + */ + uint32_t max_luminance; + + /** + * Minimum backlight in pwm. + */ + uint32_t min_backlight_pwm; + + /** + * Maximum backlight in pwm. + */ + uint32_t max_backlight_pwm; }; /** @@ -7123,6 +7056,80 @@ struct dmub_cmd_pr_enable_data { uint8_t pad[2]; }; +struct dmub_cmd_panel_polarity_enable_data { + /** + * Panel Polarity enable or disable. + */ + uint8_t enable; + /** + * OTG instance + */ + uint8_t otg_inst; + /** + * @pad: Align structure to 4 byte boundary. + */ + uint8_t pad[2]; +}; + +struct dmub_cmd_panel_polarity_reset_data { + /** + * OTG instance + */ + uint8_t otg_inst; + /** + * @pad: Align structure to 4 byte boundary. + */ + uint8_t pad[3]; +}; + +struct dmub_cmd_panel_polarity_get_bias_input { + /** + * OTG instance + */ + uint8_t otg_inst; + uint8_t pad[3]; +}; + +struct dmub_cmd_panel_polarity_get_bias_output { + /** + * Accumulated Polarity Bias + */ + int32_t accumulated_bias; +}; + +struct dmub_rb_cmd_panel_polarity_enable { + /** + * Command header. + */ + struct dmub_cmd_header header; + + struct dmub_cmd_panel_polarity_enable_data data; +}; + + +struct dmub_rb_cmd_panel_polarity_get_bias { + /** + * Command header. + */ + struct dmub_cmd_header header; + + union dmub_cmd_panel_polarity_get_bias_data { + struct dmub_cmd_panel_polarity_get_bias_input input; /**< Input */ + struct dmub_cmd_panel_polarity_get_bias_output output; /**< Output */ + uint32_t output_raw; /**< Raw data output */ + } data; +}; + +struct dmub_rb_cmd_panel_polarity_reset { + /** + * Command header. + */ + struct dmub_cmd_header header; + + struct dmub_cmd_panel_polarity_reset_data data; +}; + + /** * Definition of a DMUB_CMD__PR_ENABLE command. * Panel Replay enable/disable is controlled using action in data. @@ -7362,22 +7369,6 @@ union dmub_rb_cmd { * Elements shared with all commands. */ struct dmub_rb_cmd_common cmd_common; - /** - * Definition of a DMUB_CMD__REG_SEQ_READ_MODIFY_WRITE command. - */ - struct dmub_rb_cmd_read_modify_write read_modify_write; - /** - * Definition of a DMUB_CMD__REG_SEQ_FIELD_UPDATE_SEQ command. - */ - struct dmub_rb_cmd_reg_field_update_sequence reg_field_update_seq; - /** - * Definition of a DMUB_CMD__REG_SEQ_BURST_WRITE command. - */ - struct dmub_rb_cmd_burst_write burst_write; - /** - * Definition of a DMUB_CMD__REG_REG_WAIT command. - */ - struct dmub_rb_cmd_reg_wait reg_wait; /** * Definition of a DMUB_CMD__VBIOS_DIGX_ENCODER_CONTROL command. */ @@ -7754,6 +7745,7 @@ union dmub_rb_cmd { struct dmub_rb_cmd_pr_update_state pr_update_state; struct dmub_rb_cmd_pr_general_cmd pr_general_cmd; + /** * Definition of a DMUB_CMD__IHC command. */ @@ -7762,6 +7754,13 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__BOOT_TIME_CRC_INIT command. */ struct dmub_rb_cmd_boot_time_crc_init boot_time_crc_init; + + /** + * Definition of a DMUB_CMD__PANEL_POLARITY_ENABLE command. + */ + struct dmub_rb_cmd_panel_polarity_enable panel_polarity_enable; + struct dmub_rb_cmd_panel_polarity_get_bias panel_polarity_get_bias; + struct dmub_rb_cmd_panel_polarity_reset panel_polarity_reset; }; /** diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h index 53210e3aa0e0..827e9bd7c5cf 100644 --- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h +++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h @@ -45,6 +45,7 @@ #define DP_DEVICE_ID_BA4159 0xBA4159 #define DP_FORCE_PSRSU_CAPABILITY 0x40F +#define DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_CAP 0x370 #define DP_SINK_PSR_ACTIVE_VTOTAL 0x373 #define DP_SINK_PSR_ACTIVE_VTOTAL_CONTROL_MODE 0x375 #define DP_SOURCE_PSR_ACTIVE_VTOTAL 0x376 diff --git a/drivers/gpu/drm/amd/display/include/gpio_types.h b/drivers/gpu/drm/amd/display/include/gpio_types.h index 8dd46ed799e5..afd3fc73a911 100644 --- a/drivers/gpu/drm/amd/display/include/gpio_types.h +++ b/drivers/gpu/drm/amd/display/include/gpio_types.h @@ -277,6 +277,49 @@ enum gpio_config_type { GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE }; +struct gpio_id_offset_entry { + uint32_t offset; + uint32_t mask; + + bool check_mask; + + enum gpio_id id; + uint32_t en; +}; + +#define GPIO_ENTRY(_offset, _id, _en) \ + { \ + .offset = REG(_offset), \ + .check_mask = false, \ + .id = (_id), \ + .en = (_en), \ + } + +#define GPIO_MASK_ENTRY(_offset, _mask, _id, _en) \ + { \ + .offset = REG(_offset), \ + .mask = (_mask), \ + .check_mask = true, \ + .id = (_id), \ + .en = (_en), \ + } + +struct gpio_pin_entry { + enum gpio_id id; + uint32_t en; + + uint32_t offset; + uint32_t mask; +}; + +#define GPIO_PIN_ENTRY(_id, _en, _offset, _mask) \ + { \ + .id = (_id), \ + .en = (_en), \ + .offset = REG(_offset), \ + .mask = (_mask), \ + } + /* DDC configuration */ enum gpio_ddc_config_type { @@ -293,6 +336,11 @@ struct gpio_ddc_config { bool clock_en_bit_present; }; +struct gpio_ddc_offset_entry { + uint32_t offset; + uint32_t en; +}; + /* HPD configuration */ struct gpio_hpd_config { diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c index 1164fd96b714..f0f8e280ed30 100644 --- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c +++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp_log.c @@ -33,22 +33,28 @@ void mod_hdcp_dump_binary_message(uint8_t *msg, uint32_t msg_size, byte_size = 3, newline_size = 1, terminator_size = 1; - uint32_t line_count = msg_size / bytes_per_line, - trailing_bytes = msg_size % bytes_per_line; - uint32_t target_size = (byte_size * bytes_per_line + newline_size) * line_count + - byte_size * trailing_bytes + newline_size + terminator_size; uint32_t buf_pos = 0; uint32_t i = 0; - if (buf_size >= target_size) { - for (i = 0; i < msg_size; i++) { - if (i % bytes_per_line == 0) - buf[buf_pos++] = '\n'; - sprintf((char *)&buf[buf_pos], "%02X ", msg[i]); - buf_pos += byte_size; - } - buf[buf_pos++] = '\0'; + /* Need room for at least the terminator. */ + if (buf_size < terminator_size) + return; + + for (i = 0; i < msg_size; i++) { + uint32_t needed = byte_size + terminator_size; + + if (i % bytes_per_line == 0) + needed += newline_size; + + if (buf_pos + needed > buf_size) + break; + + if (i % bytes_per_line == 0) + buf[buf_pos++] = '\n'; + sprintf((char *)&buf[buf_pos], "%02X ", msg[i]); + buf_pos += byte_size; } + buf[buf_pos++] = '\0'; } void mod_hdcp_log_ddc_trace(struct mod_hdcp *hdcp) diff --git a/drivers/gpu/drm/amd/display/modules/power/Makefile b/drivers/gpu/drm/amd/display/modules/power/Makefile index 3000f392bdbc..0746f671eb4d 100644 --- a/drivers/gpu/drm/amd/display/modules/power/Makefile +++ b/drivers/gpu/drm/amd/display/modules/power/Makefile @@ -23,7 +23,7 @@ # Makefile for the 'power' sub-module of DAL. # -MOD_POWER = power_helpers.o power.o power_abm.o power_psr.o power_replay.o +MOD_POWER = power.o power_abm.o power_psr.o power_replay.o AMD_DAL_MOD_POWER = $(addprefix $(AMDDALPATH)/modules/power/,$(MOD_POWER)) #$(info ************ DAL POWER MODULE MAKEFILE ************) diff --git a/drivers/gpu/drm/amd/display/modules/power/power.c b/drivers/gpu/drm/amd/display/modules/power/power.c index 5659a38b3366..db101fdb11f0 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power.c +++ b/drivers/gpu/drm/amd/display/modules/power/power.c @@ -483,12 +483,7 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power, link = dc_stream_get_link(stream); if (link != NULL && dc_get_edp_link_panel_inst(dc, link, &panel_inst)) { - if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) { - aux_inst = (uint8_t)link->aux_hw_inst; - } else { - ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF); - aux_inst = (uint8_t)link->ddc->ddc_pin->hw_info.ddc_channel; - } + aux_inst = link->dc->link_srv->get_ddc_aux_inst(link); mod_power_update_backlight_on_mode_change(core_power, link, panel_inst, aux_inst, is_hdr); @@ -501,3 +496,8 @@ bool mod_power_notify_mode_change(struct mod_power *mod_power, return true; } + +bool mod_power_only_edp(const struct dc_state *context, const struct dc_stream_state *stream) +{ + return context && context->stream_count == 1 && dc_is_embedded_signal(stream->signal); +} diff --git a/drivers/gpu/drm/amd/display/modules/power/power_abm.c b/drivers/gpu/drm/amd/display/modules/power/power_abm.c index a1a0563598b5..b9447cb7485b 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_abm.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_abm.c @@ -849,12 +849,7 @@ bool mod_power_set_backlight_nits(struct mod_power *mod_power, core_power = MOD_POWER_TO_CORE(mod_power); link = dc_stream_get_link(stream); - if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) { - aux_inst = (uint8_t)link->aux_hw_inst; - } else { - ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF); - aux_inst = (uint8_t)link->ddc->ddc_pin->hw_info.ddc_channel; - } + aux_inst = link->dc->link_srv->get_ddc_aux_inst(link); if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &panel_inst)) return false; @@ -941,12 +936,7 @@ bool mod_power_set_backlight_percent(struct mod_power *mod_power, core_power = MOD_POWER_TO_CORE(mod_power); link = dc_stream_get_link(stream); - if (link->ctx->dc->config.dp_connector_no_native_i2c && link->no_ddc_pin) { - aux_inst = (uint8_t)link->aux_hw_inst; - } else { - ASSERT(link->ddc->ddc_pin->hw_info.ddc_channel <= 0xFF); - aux_inst = (uint8_t)link->ddc->ddc_pin->hw_info.ddc_channel; - } + aux_inst = link->dc->link_srv->get_ddc_aux_inst(link); if (!dc_get_edp_link_panel_inst(core_power->dc, stream->link, &panel_inst)) return false; diff --git a/drivers/gpu/drm/amd/display/modules/power/power_replay.c b/drivers/gpu/drm/amd/display/modules/power/power_replay.c index 983be9759e74..e782501442c4 100644 --- a/drivers/gpu/drm/amd/display/modules/power/power_replay.c +++ b/drivers/gpu/drm/amd/display/modules/power/power_replay.c @@ -175,11 +175,10 @@ static bool mod_power_update_replay_active_status(unsigned int active_replay_eve if (link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]) *coasting_vtotal = link->replay_settings.coasting_vtotal_table[PR_COASTING_TYPE_TEST_HARNESS]; - if (link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]) { - ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS] <= 0xFFFF); - *frame_skip_number = - (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; - } + + ASSERT(link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS] <= 0xFFFF); + *frame_skip_number = + (uint16_t)link->replay_settings.frame_skip_number_table[PR_COASTING_TYPE_TEST_HARNESS]; /* During the ultra sleep mode testing, disable the timing sync in short vblank mode */ if (active_replay_events & (replay_event_test_harness_enable_replay)) { diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index 3fd38323a88b..10396018afb3 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -471,10 +471,7 @@ struct amd_ip_funcs { void (*complete)(struct amdgpu_ip_block *ip_block); bool (*is_idle)(struct amdgpu_ip_block *ip_block); int (*wait_for_idle)(struct amdgpu_ip_block *ip_block); - bool (*check_soft_reset)(struct amdgpu_ip_block *ip_block); - int (*pre_soft_reset)(struct amdgpu_ip_block *ip_block); int (*soft_reset)(struct amdgpu_ip_block *ip_block); - int (*post_soft_reset)(struct amdgpu_ip_block *ip_block); int (*set_clockgating_state)(struct amdgpu_ip_block *ip_block, enum amd_clockgating_state state); int (*set_powergating_state)(struct amdgpu_ip_block *ip_block, diff --git a/drivers/gpu/drm/amd/include/asic_reg/sdma/sdma_4_4_2_offset.h b/drivers/gpu/drm/amd/include/asic_reg/sdma/sdma_4_4_2_offset.h index ead81aeffd67..11c32e4274fa 100644 --- a/drivers/gpu/drm/amd/include/asic_reg/sdma/sdma_4_4_2_offset.h +++ b/drivers/gpu/drm/amd/include/asic_reg/sdma/sdma_4_4_2_offset.h @@ -493,6 +493,10 @@ #define regSDMA_RLC0_MIDCMD_DATA10_BASE_IDX 0 #define regSDMA_RLC0_MIDCMD_CNTL 0x017b #define regSDMA_RLC0_MIDCMD_CNTL_BASE_IDX 0 +#define regSDMA_RLC0_UTILIZATION_LO 0x017c +#define regSDMA_RLC0_UTILIZATION_LO_BASE_IDX 0 +#define regSDMA_RLC0_UTILIZATION_HI 0x017d +#define regSDMA_RLC0_UTILIZATION_HI_BASE_IDX 0 #define regSDMA_RLC1_RB_CNTL 0x0188 #define regSDMA_RLC1_RB_CNTL_BASE_IDX 0 #define regSDMA_RLC1_RB_BASE 0x0189 diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 44e225e097d0..965b50c8ca30 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -339,6 +339,9 @@ struct kfd2kgd_calls { uint32_t *ptl_state, enum amdgpu_ptl_fmt *fmt1, enum amdgpu_ptl_fmt *fmt2); + int (*hqd_sdma_get_counter)(struct amdgpu_device *adev, + void *mqd, uint32_t num_sdma_queues_per_eng, + uint64_t *val); }; #endif /* KGD_KFD_INTERFACE_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/include/mes_v11_api_def.h b/drivers/gpu/drm/amd/include/mes_v11_api_def.h index f9629d42ada2..b06412ac8583 100644 --- a/drivers/gpu/drm/amd/include/mes_v11_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v11_api_def.h @@ -238,8 +238,9 @@ union MESAPI_SET_HW_RESOURCES { uint32_t enable_mes_sch_stb_log : 1; uint32_t limit_single_process : 1; uint32_t is_strix_tmz_wa_enabled :1; - uint32_t enable_lr_compute_wa : 1; - uint32_t reserved : 12; + uint32_t enable_lr_compute_wa : 2; + uint32_t enable_compute_pipe_reset : 1; + uint32_t reserved : 10; }; uint32_t uint32_t_all; }; @@ -427,6 +428,7 @@ union MESAPI__SUSPEND { uint32_t suspend_fence_value; struct MES_API_STATUS api_status; + uint32_t doorbell_offset; }; uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; @@ -444,6 +446,7 @@ union MESAPI__RESUME { uint64_t gang_context_addr; struct MES_API_STATUS api_status; + uint32_t doorbell_offset; }; uint32_t max_dwords_in_api[API_FRAME_SIZE_IN_DWORDS]; diff --git a/drivers/gpu/drm/amd/include/mes_v12_api_def.h b/drivers/gpu/drm/amd/include/mes_v12_api_def.h index e541a43714a1..cb7ebdfffeeb 100644 --- a/drivers/gpu/drm/amd/include/mes_v12_api_def.h +++ b/drivers/gpu/drm/amd/include/mes_v12_api_def.h @@ -294,8 +294,9 @@ union MESAPI_SET_HW_RESOURCES { uint32_t limit_single_process : 1; uint32_t unmapped_doorbell_handling: 2; uint32_t enable_mes_fence_int: 1; - uint32_t enable_lr_compute_wa : 1; - uint32_t reserved : 9; + uint32_t enable_lr_compute_wa : 2; + uint32_t enable_compute_pipe_reset : 1; + uint32_t reserved : 7; }; uint32_t uint32_all; }; diff --git a/drivers/gpu/drm/amd/include/soc15_hw_ip.h b/drivers/gpu/drm/amd/include/soc15_hw_ip.h index a20e59584dde..60f588dd0130 100644 --- a/drivers/gpu/drm/amd/include/soc15_hw_ip.h +++ b/drivers/gpu/drm/amd/include/soc15_hw_ip.h @@ -44,6 +44,7 @@ #define SDPMUX_HWID 19 #define NTB_HWID 20 #define VPE_HWID 21 +#define UMSCH_HWID 22 #define IOHC_HWID 24 #define L2IMU_HWID 28 #define VCE_HWID 32 diff --git a/drivers/gpu/drm/amd/include/v9_structs.h b/drivers/gpu/drm/amd/include/v9_structs.h index a2f81b9c38af..e0d387f08576 100644 --- a/drivers/gpu/drm/amd/include/v9_structs.h +++ b/drivers/gpu/drm/amd/include/v9_structs.h @@ -69,8 +69,8 @@ struct v9_sdma_mqd { uint32_t sdmax_rlcx_midcmd_cntl; uint32_t reserved_42; uint32_t reserved_43; - uint32_t reserved_44; - uint32_t reserved_45; + uint32_t sdmax_rlcx_utilization_lo; + uint32_t sdmax_rlcx_utilization_hi; uint32_t reserved_46; uint32_t reserved_47; uint32_t reserved_48; diff --git a/drivers/gpu/drm/amd/pm/amdgpu_pm.c b/drivers/gpu/drm/amd/pm/amdgpu_pm.c index f43d09769320..f5a5d72b4108 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_pm.c @@ -41,6 +41,8 @@ #define DEVICE_ATTR_IS(_name) (attr_id == device_attr_id__##_name) +#define power_2_mwatt(power) (((power) >> 8) * 1000 + ((power) & 0xff)) + struct od_attribute { struct kobj_attribute attribute; struct list_head entry; @@ -98,6 +100,37 @@ const char * const amdgpu_pp_profile_name[] = { "UNCAPPED", }; +static int amdgpu_pm_parse_long_params(char *str, long *params, + uint32_t max_params, + uint32_t *num_params) +{ + const char delimiter[] = { ' ', '\n', '\0' }; + uint32_t count = 0; + char *sub_str; + int ret; + + if (!params || !num_params) + return -EINVAL; + + while ((sub_str = strsep(&str, delimiter)) != NULL) { + if (strlen(sub_str) == 0) + continue; + if (count >= max_params) + return -EINVAL; + ret = kstrtol(sub_str, 0, ¶ms[count]); + if (ret) + return -EINVAL; + count++; + if (!str) + break; + while (isspace(*str)) + str++; + } + *num_params = count; + + return 0; +} + /** * amdgpu_pm_dev_state_check - Check if device can be accessed. * @adev: Target device. @@ -767,8 +800,6 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, long parameter[64]; char buf_cpy[128]; char *tmp_str; - char *sub_str; - const char delimiter[3] = {' ', '\n', '\0'}; uint32_t type; if (count > 127 || count == 0) @@ -803,22 +834,10 @@ static ssize_t amdgpu_set_pp_od_clk_voltage(struct device *dev, tmp_str++; while (isspace(*++tmp_str)); - while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { - if (strlen(sub_str) == 0) - continue; - if (parameter_size >= ARRAY_SIZE(parameter)) - return -EINVAL; - ret = kstrtol(sub_str, 0, ¶meter[parameter_size]); - if (ret) - return -EINVAL; - parameter_size++; - - if (!tmp_str) - break; - - while (isspace(*tmp_str)) - tmp_str++; - } + ret = amdgpu_pm_parse_long_params( + tmp_str, parameter, ARRAY_SIZE(parameter), ¶meter_size); + if (ret) + return ret; ret = amdgpu_pm_get_access(adev); if (ret < 0) @@ -1391,11 +1410,9 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, struct amdgpu_device *adev = drm_to_adev(ddev); uint32_t parameter_size = 0; long parameter[64]; - char *sub_str, buf_cpy[128]; - char *tmp_str; + char buf_cpy[128]; char tmp[2]; long int profile_mode = 0; - const char delimiter[3] = {' ', '\n', '\0'}; /* Reject empty/whitespace strings - fuzzing found this is not validated */ if (count == 0 || sysfs_streq(buf, "")) @@ -1413,19 +1430,11 @@ static ssize_t amdgpu_set_pp_power_profile_mode(struct device *dev, while (isspace(*buf)) buf++; strscpy(buf_cpy, buf, sizeof(buf_cpy)); - tmp_str = buf_cpy; - while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { - if (strlen(sub_str) == 0) - continue; - ret = kstrtol(sub_str, 0, ¶meter[parameter_size]); - if (ret) - return -EINVAL; - parameter_size++; - if (!tmp_str) - break; - while (isspace(*tmp_str)) - tmp_str++; - } + ret = amdgpu_pm_parse_long_params(buf_cpy, parameter, + ARRAY_SIZE(parameter) - 1, + ¶meter_size); + if (ret) + return ret; } parameter[parameter_size] = profile_mode; @@ -2696,6 +2705,11 @@ static int default_attr_update(struct amdgpu_device *adev, struct amdgpu_device_ gc_ver != IP_VERSION(9, 4, 3)) || gc_ver < IP_VERSION(9, 0, 0)) *states = ATTR_STATE_UNSUPPORTED; + + if (adev->scpm_enabled) { + dev_attr->attr.mode &= ~S_IWUGO; + dev_attr->store = NULL; + } } else if (DEVICE_ATTR_IS(gpu_metrics)) { if (gc_ver < IP_VERSION(9, 1, 0)) *states = ATTR_STATE_UNSUPPORTED; @@ -3349,7 +3363,6 @@ static int amdgpu_hwmon_get_power(struct device *dev, enum amd_pp_sensors sensor) { struct amdgpu_device *adev = dev_get_drvdata(dev); - unsigned int uw; u32 query = 0; int r; @@ -3358,9 +3371,7 @@ static int amdgpu_hwmon_get_power(struct device *dev, return r; /* convert to microwatts */ - uw = (query >> 8) * 1000000 + (query & 0xff) * 1000; - - return uw; + return power_2_mwatt(query) * 1000; } static ssize_t amdgpu_hwmon_show_power_avg(struct device *dev, @@ -3954,18 +3965,14 @@ static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev, return size; } -static int parse_input_od_command_lines(const char *buf, - size_t count, - u32 *type, - long *params, - size_t params_max, +static int parse_input_od_command_lines(const char *buf, size_t count, + u32 *type, long *params, + uint32_t max_params, uint32_t *num_of_params) { - const char delimiter[3] = {' ', '\n', '\0'}; uint32_t parameter_size = 0; char buf_cpy[128] = {0}; - char *tmp_str, *sub_str; - int ret; + char *tmp_str; if (count > sizeof(buf_cpy) - 1) return -EINVAL; @@ -3990,28 +3997,8 @@ static int parse_input_od_command_lines(const char *buf, break; } - while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) { - if (strlen(sub_str) == 0) - continue; - - if (parameter_size >= params_max) - return -EINVAL; - - ret = kstrtol(sub_str, 0, ¶ms[parameter_size]); - if (ret) - return -EINVAL; - parameter_size++; - - if (!tmp_str) - break; - - while (isspace(*tmp_str)) - tmp_str++; - } - - *num_of_params = parameter_size; - - return 0; + return amdgpu_pm_parse_long_params(tmp_str, params, max_params, + num_of_params); } static int @@ -4024,10 +4011,7 @@ amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev, long parameter[64]; int ret; - ret = parse_input_od_command_lines(in_buf, - count, - &cmd_type, - parameter, + ret = parse_input_od_command_lines(in_buf, count, &cmd_type, parameter, ARRAY_SIZE(parameter), ¶meter_size); if (ret) @@ -4903,7 +4887,7 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a { uint32_t mp1_ver = amdgpu_ip_version(adev, MP1_HWIP, 0); uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0); - uint32_t value; + uint32_t value, mwatt, centiwatt; uint64_t value64 = 0; uint32_t query = 0; int size; @@ -4928,17 +4912,21 @@ static int amdgpu_debugfs_pm_info_pp(struct seq_file *m, struct amdgpu_device *a seq_printf(m, "\t%u mV (VDDNB)\n", value); size = sizeof(uint32_t); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_AVG_POWER, (void *)&query, &size)) { + mwatt = power_2_mwatt(query); + centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); if (adev->flags & AMD_IS_APU) - seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (average SoC including CPU)\n", centiwatt / 100, centiwatt % 100); else - seq_printf(m, "\t%u.%02u W (average SoC)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (average SoC)\n", centiwatt / 100, centiwatt % 100); } size = sizeof(uint32_t); if (!amdgpu_dpm_read_sensor(adev, AMDGPU_PP_SENSOR_GPU_INPUT_POWER, (void *)&query, &size)) { + mwatt = power_2_mwatt(query); + centiwatt = DIV_ROUND_CLOSEST(mwatt, 10); if (adev->flags & AMD_IS_APU) - seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (current SoC including CPU)\n", centiwatt / 100, centiwatt % 100); else - seq_printf(m, "\t%u.%02u W (current SoC)\n", query >> 8, query & 0xff); + seq_printf(m, "\t%u.%02u W (current SoC)\n", centiwatt / 100, centiwatt % 100); } size = sizeof(value); seq_printf(m, "\n"); diff --git a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c index 6f5c27bdc1e9..7c70e228a5ba 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c @@ -660,25 +660,20 @@ static int amd_powerplay_reset(void *handle) static int pp_dpm_set_pp_table(void *handle, const char *buf, size_t size) { struct pp_hwmgr *hwmgr = handle; + void *hardcode_pp_table; int ret = -ENOMEM; - if (!hwmgr || !hwmgr->pm_en) + if (!hwmgr || !hwmgr->pm_en || !buf || !size || size > U32_MAX) return -EINVAL; - if (size > hwmgr->soft_pp_table_size) - return -EINVAL; - - if (!hwmgr->hardcode_pp_table) { - hwmgr->hardcode_pp_table = kmemdup(hwmgr->soft_pp_table, - hwmgr->soft_pp_table_size, - GFP_KERNEL); - if (!hwmgr->hardcode_pp_table) - return ret; - } - - memcpy(hwmgr->hardcode_pp_table, buf, size); + hardcode_pp_table = kmemdup(buf, size, GFP_KERNEL); + if (!hardcode_pp_table) + return ret; + kfree(hwmgr->hardcode_pp_table); + hwmgr->hardcode_pp_table = hardcode_pp_table; hwmgr->soft_pp_table = hwmgr->hardcode_pp_table; + hwmgr->soft_pp_table_size = size; ret = amd_powerplay_reset(handle); if (ret) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c index ce166a7f8e42..4b796d60b03d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c @@ -46,16 +46,22 @@ union voltage_object_info { static int atomctrl_retrieve_ac_timing( uint8_t index, ATOM_INIT_REG_BLOCK *reg_block, + u8 *table_end, pp_atomctrl_mc_reg_table *table) { uint32_t i, j; + u16 stride = le16_to_cpu(reg_block->usRegDataBlkSize); uint8_t tmem_id; ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) ((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize)); uint8_t num_ranges = 0; - while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK && + if (stride < sizeof(uint32_t)) + return -EINVAL; + + while ((uint8_t *)reg_data + sizeof(uint32_t) <= table_end && + *(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK && num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) { tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT); @@ -67,6 +73,10 @@ static int atomctrl_retrieve_ac_timing( for (i = 0, j = 1; i < table->last; i++) { if ((table->mc_reg_address[i].uc_pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) { + if ((uint8_t *)reg_data + + (j + 1) * sizeof(uint32_t) > table_end) + return -EINVAL; + table->mc_reg_table_entry[num_ranges].mc_data[i] = (uint32_t)*((uint32_t *)reg_data + j); j++; @@ -81,11 +91,13 @@ static int atomctrl_retrieve_ac_timing( } reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) - ((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ; + ((uint8_t *)reg_data + stride); } - PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK), - "Invalid VramInfo table.", return -1); + if ((uint8_t *)reg_data + sizeof(uint32_t) > table_end || + *(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK) + return -EINVAL; + table->num_entries = num_ranges; return 0; @@ -136,6 +148,7 @@ int atomctrl_initialize_mc_reg_table( { ATOM_VRAM_INFO_HEADER_V2_1 *vram_info; ATOM_INIT_REG_BLOCK *reg_block; + u8 *table_end; int result = 0; u8 frev, crev; u16 size; @@ -157,6 +170,7 @@ int atomctrl_initialize_mc_reg_table( } if (0 == result) { + table_end = (uint8_t *)vram_info + size; reg_block = (ATOM_INIT_REG_BLOCK *) ((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset)); result = atomctrl_set_mc_reg_address_table(reg_block, table); @@ -164,7 +178,7 @@ int atomctrl_initialize_mc_reg_table( if (0 == result) { result = atomctrl_retrieve_ac_timing(module_index, - reg_block, table); + reg_block, table_end, table); } return result; @@ -177,6 +191,7 @@ int atomctrl_initialize_mc_reg_table_v2_2( { ATOM_VRAM_INFO_HEADER_V2_2 *vram_info; ATOM_INIT_REG_BLOCK *reg_block; + u8 *table_end; int result = 0; u8 frev, crev; u16 size; @@ -198,6 +213,7 @@ int atomctrl_initialize_mc_reg_table_v2_2( } if (0 == result) { + table_end = (uint8_t *)vram_info + size; reg_block = (ATOM_INIT_REG_BLOCK *) ((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset)); result = atomctrl_set_mc_reg_address_table(reg_block, table); @@ -205,7 +221,7 @@ int atomctrl_initialize_mc_reg_table_v2_2( if (0 == result) { result = atomctrl_retrieve_ac_timing(module_index, - reg_block, table); + reg_block, table_end, table); } return result; @@ -268,15 +284,21 @@ static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3( unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]); uint8_t *start = (uint8_t *)voltage_object_info_table; - while (offset < size) { + while (offset + sizeof(ATOM_VOLTAGE_OBJECT_HEADER_V3) <= size) { const ATOM_VOLTAGE_OBJECT_V3 *voltage_object = (const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); + u16 obj_size; + + obj_size = le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize); + if (obj_size < sizeof(voltage_object->asGpioVoltageObj.sHeader) || + offset + obj_size > size) + break; if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType && voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode) return voltage_object; - offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize); + offset += obj_size; } return NULL; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c index 6120f14caab0..69aee8661d1e 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c @@ -36,16 +36,21 @@ static const union atom_voltage_object_v4 *pp_atomfwctrl_lookup_voltage_type_v4( offsetof(struct atom_voltage_objects_info_v4_1, voltage_object[0]); unsigned long start = (unsigned long)voltage_object_info_table; - while (offset < size) { + while (offset + sizeof(struct atom_voltage_object_header_v4) <= size) { const union atom_voltage_object_v4 *voltage_object = (const union atom_voltage_object_v4 *)(start + offset); + u16 obj_size; + + obj_size = le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size); + if (obj_size < sizeof(voltage_object->gpio_voltage_obj.header) || + offset + obj_size > size) + break; if (voltage_type == voltage_object->gpio_voltage_obj.header.voltage_type && voltage_mode == voltage_object->gpio_voltage_obj.header.voltage_mode) return voltage_object; - offset += le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size); - + offset += obj_size; } return NULL; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c index 6fcca65bd7d4..c5673077c895 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c @@ -150,6 +150,368 @@ static const void *get_powerplay_table(struct pp_hwmgr *hwmgr) return table_address; } +static bool tonga_pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset, + size_t size) +{ + size_t table_size = hwmgr->soft_pp_table_size; + + return offset <= table_size && size <= table_size - offset; +} + +static int get_tonga_subtable(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + u16 table_offset, size_t table_size, const void **table) +{ + PP_ASSERT_WITH_CODE((table_offset != 0), + "Invalid PowerPlay Table!", return -1); + PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *table = (const void *)(((unsigned long)powerplay_table) + table_offset); + + return 0; +} + +static int validate_tonga_table_entries(struct pp_hwmgr *hwmgr, + u16 table_offset, size_t entries_offset, + u8 num_entries, size_t entry_size) +{ + size_t table_size; + + PP_ASSERT_WITH_CODE((num_entries != 0), + "Invalid PowerPlay Table!", return -1); + + table_size = entries_offset + num_entries * entry_size; + PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + return 0; +} + +static int get_tonga_voltage_lookup_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + u16 table_offset, uint32_t max_levels, + const ATOM_Tonga_Voltage_Lookup_Table **lookup_table) +{ + const ATOM_Tonga_Voltage_Lookup_Table *table; + size_t table_size; + int ret; + + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + PP_ASSERT_WITH_CODE((table->ucNumEntries != 0 && + table->ucNumEntries <= max_levels), + "Invalid PowerPlay Table!", return -1); + + table_size = offsetof(ATOM_Tonga_Voltage_Lookup_Table, entries) + + table->ucNumEntries * sizeof(ATOM_Tonga_Voltage_Lookup_Record); + PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *lookup_table = table; + + return 0; +} + +static int get_tonga_mclk_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_MCLK_Dependency_Table **mclk_dep_table) +{ + const ATOM_Tonga_MCLK_Dependency_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usMclkDependencyTableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_tonga_table_entries(hwmgr, table_offset, + offsetof(ATOM_Tonga_MCLK_Dependency_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Tonga_MCLK_Dependency_Record)); + if (ret) + return ret; + + *mclk_dep_table = table; + + return 0; +} + +static int get_tonga_mm_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_MM_Dependency_Table **mm_dep_table) +{ + const ATOM_Tonga_MM_Dependency_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usMMDependencyTableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_tonga_table_entries(hwmgr, table_offset, + offsetof(ATOM_Tonga_MM_Dependency_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Tonga_MM_Dependency_Record)); + if (ret) + return ret; + + *mm_dep_table = table; + + return 0; +} + +static int get_tonga_sclk_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const PPTable_Generic_SubTable_Header **sclk_dep_table) +{ + const PPTable_Generic_SubTable_Header *header; + u16 table_offset; + size_t entries_offset; + size_t entry_size; + u8 num_entries; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usSclkDependencyTableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*header), (const void **)&header); + if (ret) + return ret; + + if (header->ucRevId < 1) { + const ATOM_Tonga_SCLK_Dependency_Table *table = + (const ATOM_Tonga_SCLK_Dependency_Table *)header; + + entries_offset = offsetof(ATOM_Tonga_SCLK_Dependency_Table, entries); + entry_size = sizeof(ATOM_Tonga_SCLK_Dependency_Record); + num_entries = table->ucNumEntries; + } else { + const ATOM_Polaris_SCLK_Dependency_Table *table = + (const ATOM_Polaris_SCLK_Dependency_Table *)header; + + entries_offset = offsetof(ATOM_Polaris_SCLK_Dependency_Table, entries); + entry_size = sizeof(ATOM_Polaris_SCLK_Dependency_Record); + num_entries = table->ucNumEntries; + } + + ret = validate_tonga_table_entries(hwmgr, table_offset, entries_offset, + num_entries, entry_size); + if (ret) + return ret; + + *sclk_dep_table = header; + + return 0; +} + +static int get_tonga_pcie_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const PPTable_Generic_SubTable_Header **pcie_table) +{ + const PPTable_Generic_SubTable_Header *header; + u16 table_offset; + size_t entries_offset; + size_t entry_size; + u8 num_entries; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usPCIETableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*header), (const void **)&header); + if (ret) + return ret; + + if (header->ucRevId < 1) { + const ATOM_Tonga_PCIE_Table *table = + (const ATOM_Tonga_PCIE_Table *)header; + + entries_offset = offsetof(ATOM_Tonga_PCIE_Table, entries); + entry_size = sizeof(ATOM_Tonga_PCIE_Record); + num_entries = table->ucNumEntries; + } else { + const ATOM_Polaris10_PCIE_Table *table = + (const ATOM_Polaris10_PCIE_Table *)header; + + entries_offset = offsetof(ATOM_Polaris10_PCIE_Table, entries); + entry_size = sizeof(ATOM_Polaris10_PCIE_Record); + num_entries = table->ucNumEntries; + } + + ret = validate_tonga_table_entries(hwmgr, table_offset, entries_offset, + num_entries, entry_size); + if (ret) + return ret; + + *pcie_table = header; + + return 0; +} + +static int get_tonga_hard_limit_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_Hard_Limit_Table **hard_limit_table) +{ + const ATOM_Tonga_Hard_Limit_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usHardLimitTableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_tonga_table_entries(hwmgr, table_offset, + offsetof(ATOM_Tonga_Hard_Limit_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Tonga_Hard_Limit_Record)); + if (ret) + return ret; + + *hard_limit_table = table; + + return 0; +} + +static int get_tonga_thermal_controller_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_Thermal_Controller **thermal_controller) +{ + u16 table_offset; + + table_offset = le16_to_cpu(powerplay_table->usThermalControllerOffset); + + return get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(**thermal_controller), + (const void **)thermal_controller); +} + +static int get_tonga_fan_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const PPTable_Generic_SubTable_Header **fan_table) +{ + const PPTable_Generic_SubTable_Header *header; + u16 table_offset; + size_t table_size; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usFanTableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*header), (const void **)&header); + if (ret) + return ret; + + if (header->ucRevId < 8) + table_size = sizeof(ATOM_Tonga_Fan_Table); + else if (header->ucRevId == 8) + table_size = sizeof(ATOM_Fiji_Fan_Table); + else + table_size = sizeof(ATOM_Polaris_Fan_Table); + + PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *fan_table = header; + + return 0; +} + +static int get_tonga_power_tune_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const PPTable_Generic_SubTable_Header **power_tune_table) +{ + const PPTable_Generic_SubTable_Header *header; + u16 table_offset; + size_t table_size; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usPowerTuneTableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*header), (const void **)&header); + if (ret) + return ret; + + if (header->ucRevId < 3) + table_size = sizeof(ATOM_Tonga_PowerTune_Table); + else if (header->ucRevId < 4) + table_size = sizeof(ATOM_Fiji_PowerTune_Table); + else + table_size = sizeof(ATOM_Polaris_PowerTune_Table); + + PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *power_tune_table = header; + + return 0; +} + +static int get_tonga_ppm_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_PPM_Table **ppm_table) +{ + u16 table_offset; + + table_offset = le16_to_cpu(powerplay_table->usPPMTableOffset); + + return get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(**ppm_table), (const void **)ppm_table); +} + +static int get_tonga_gpio_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_GPIO_Table **gpio_table) +{ + u16 table_offset; + + table_offset = le16_to_cpu(powerplay_table->usGPIOTableOffset); + + return get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(**gpio_table), (const void **)gpio_table); +} + +static int get_tonga_vce_state_table(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_VCE_State_Table **vce_state_table) +{ + const ATOM_Tonga_VCE_State_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usVCEStateTableOffset); + ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_tonga_table_entries(hwmgr, table_offset, + offsetof(ATOM_Tonga_VCE_State_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Tonga_VCE_State_Record)); + if (ret) + return ret; + + *vce_state_table = table; + + return 0; +} + static int get_vddc_lookup_table( struct pp_hwmgr *hwmgr, phm_ppt_v1_voltage_lookup_table **lookup_table, @@ -158,6 +520,7 @@ static int get_vddc_lookup_table( ) { uint32_t i; + uint32_t num_entries; phm_ppt_v1_voltage_lookup_table *table; phm_ppt_v1_voltage_lookup_record *record; ATOM_Tonga_Voltage_Lookup_Record *atom_record; @@ -165,13 +528,22 @@ static int get_vddc_lookup_table( PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries), "Invalid CAC Leakage PowerPlay Table!", return 1); - table = kzalloc_flex(*table, entries, max_levels); + num_entries = min_t(uint32_t, vddc_lookup_pp_tables->ucNumEntries, + min_t(uint32_t, max_levels, + pp_entries_max(hwmgr, vddc_lookup_pp_tables, + sizeof(*vddc_lookup_pp_tables), + sizeof(ATOM_Tonga_Voltage_Lookup_Record)))); + if (num_entries < vddc_lookup_pp_tables->ucNumEntries) + pr_warn("amdgpu: VddcLookup table: clamping ucNumEntries %u -> %u\n", + vddc_lookup_pp_tables->ucNumEntries, num_entries); + + table = kzalloc_flex(*table, entries, num_entries); if (!table) return -ENOMEM; - table->count = vddc_lookup_pp_tables->ucNumEntries; + table->count = num_entries; - for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( phm_ppt_v1_voltage_lookup_record, entries, table, i); @@ -198,7 +570,7 @@ static int get_vddc_lookup_table( */ static int get_platform_power_management_table( struct pp_hwmgr *hwmgr, - ATOM_Tonga_PPM_Table *atom_ppm_table) + const ATOM_Tonga_PPM_Table *atom_ppm_table) { struct phm_ppm_table *ptr = kzalloc_obj(*ptr); struct phm_ppt_v1_information *pp_table_information = @@ -246,7 +618,7 @@ static int init_dpm_2_parameters( { int result = 0; struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable); - ATOM_Tonga_PPM_Table *atom_ppm_table; + const ATOM_Tonga_PPM_Table *atom_ppm_table; uint32_t disable_ppm = 0; uint32_t disable_power_control = 0; @@ -275,30 +647,39 @@ static int init_dpm_2_parameters( } if (0 != powerplay_table->usVddcLookupTableOffset) { - const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable = - (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usVddcLookupTableOffset)); + const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable; - result = get_vddc_lookup_table(hwmgr, - &pp_table_information->vddc_lookup_table, pVddcCACTable, 16); + result = get_tonga_voltage_lookup_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usVddcLookupTableOffset), + 16, &pVddcCACTable); + if (!result) + result = get_vddc_lookup_table(hwmgr, + &pp_table_information->vddc_lookup_table, + pVddcCACTable, 16); } - if (0 != powerplay_table->usVddgfxLookupTableOffset) { - const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable = - (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset)); + if (!result && 0 != powerplay_table->usVddgfxLookupTableOffset) { + const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable; - result = get_vddc_lookup_table(hwmgr, - &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16); + result = get_tonga_voltage_lookup_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset), + 16, &pVddgfxCACTable); + if (!result) + result = get_vddc_lookup_table(hwmgr, + &pp_table_information->vddgfx_lookup_table, + pVddgfxCACTable, 16); } disable_ppm = 0; if (0 == disable_ppm) { - atom_ppm_table = (ATOM_Tonga_PPM_Table *) - (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset)); - if (0 != powerplay_table->usPPMTableOffset) { - if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) { + int ret; + + ret = get_tonga_ppm_table(hwmgr, powerplay_table, + &atom_ppm_table); + if (!ret && + get_platform_power_management_table(hwmgr, + atom_ppm_table) == 0) { phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EnablePlatformPowerManagement); } @@ -363,6 +744,7 @@ static int get_mclk_voltage_dependency_table( ) { uint32_t i; + uint32_t num_entries; phm_ppt_v1_clock_voltage_dependency_table *mclk_table; phm_ppt_v1_clock_voltage_dependency_record *mclk_table_record; ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record; @@ -370,14 +752,21 @@ static int get_mclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - mclk_table = kzalloc_flex(*mclk_table, entries, - mclk_dep_table->ucNumEntries); + num_entries = min_t(uint32_t, mclk_dep_table->ucNumEntries, + pp_entries_max(hwmgr, mclk_dep_table, + sizeof(*mclk_dep_table), + sizeof(ATOM_Tonga_MCLK_Dependency_Record))); + if (num_entries < mclk_dep_table->ucNumEntries) + pr_warn("amdgpu: MCLK dependency table: clamping ucNumEntries %u -> %u\n", + mclk_dep_table->ucNumEntries, num_entries); + + mclk_table = kzalloc_flex(*mclk_table, entries, num_entries); if (!mclk_table) return -ENOMEM; - mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries; + mclk_table->count = num_entries; - for (i = 0; i < mclk_dep_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { mclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( phm_ppt_v1_clock_voltage_dependency_record, entries, mclk_table, i); @@ -403,6 +792,7 @@ static int get_sclk_voltage_dependency_table( ) { uint32_t i; + uint32_t num_entries; phm_ppt_v1_clock_voltage_dependency_table *sclk_table; phm_ppt_v1_clock_voltage_dependency_record *sclk_table_record; @@ -414,14 +804,21 @@ static int get_sclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - sclk_table = kzalloc_flex(*sclk_table, entries, - tonga_table->ucNumEntries); + num_entries = min_t(uint32_t, tonga_table->ucNumEntries, + pp_entries_max(hwmgr, tonga_table, + sizeof(*tonga_table), + sizeof(ATOM_Tonga_SCLK_Dependency_Record))); + if (num_entries < tonga_table->ucNumEntries) + pr_warn("amdgpu: Tonga SCLK dependency table: clamping ucNumEntries %u -> %u\n", + tonga_table->ucNumEntries, num_entries); + + sclk_table = kzalloc_flex(*sclk_table, entries, num_entries); if (!sclk_table) return -ENOMEM; - sclk_table->count = (uint32_t)tonga_table->ucNumEntries; + sclk_table->count = num_entries; - for (i = 0; i < tonga_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( ATOM_Tonga_SCLK_Dependency_Record, entries, tonga_table, i); @@ -443,14 +840,21 @@ static int get_sclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - sclk_table = kzalloc_flex(*sclk_table, entries, - polaris_table->ucNumEntries); + num_entries = min_t(uint32_t, polaris_table->ucNumEntries, + pp_entries_max(hwmgr, polaris_table, + sizeof(*polaris_table), + sizeof(ATOM_Polaris_SCLK_Dependency_Record))); + if (num_entries < polaris_table->ucNumEntries) + pr_warn("amdgpu: Polaris SCLK dependency table: clamping ucNumEntries %u -> %u\n", + polaris_table->ucNumEntries, num_entries); + + sclk_table = kzalloc_flex(*sclk_table, entries, num_entries); if (!sclk_table) return -ENOMEM; - sclk_table->count = (uint32_t)polaris_table->ucNumEntries; + sclk_table->count = num_entries; - for (i = 0; i < polaris_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( ATOM_Polaris_SCLK_Dependency_Record, entries, polaris_table, i); @@ -715,20 +1119,29 @@ static int get_mm_clock_voltage_table( ) { uint32_t i; + uint32_t num_entries; const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record; phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table; phm_ppt_v1_mm_clock_voltage_dependency_record *mm_table_record; PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries), "Invalid PowerPlay Table!", return -1); - mm_table = kzalloc_flex(*mm_table, entries, - mm_dependency_table->ucNumEntries); + + num_entries = min_t(uint32_t, mm_dependency_table->ucNumEntries, + pp_entries_max(hwmgr, mm_dependency_table, + sizeof(*mm_dependency_table), + sizeof(ATOM_Tonga_MM_Dependency_Record))); + if (num_entries < mm_dependency_table->ucNumEntries) + pr_warn("amdgpu: MM dependency table: clamping ucNumEntries %u -> %u\n", + mm_dependency_table->ucNumEntries, num_entries); + + mm_table = kzalloc_flex(*mm_table, entries, num_entries); if (!mm_table) return -ENOMEM; - mm_table->count = mm_dependency_table->ucNumEntries; + mm_table->count = num_entries; - for (i = 0; i < mm_dependency_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { mm_dependency_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( ATOM_Tonga_MM_Dependency_Record, entries, mm_dependency_table, i); @@ -789,28 +1202,13 @@ static int init_clock_voltage_dependency( int result = 0; struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable); - - const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table = - (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usMMDependencyTableOffset)); - const PPTable_Generic_SubTable_Header *pPowerTuneTable = - (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usPowerTuneTableOffset)); - const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = - (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usMclkDependencyTableOffset)); - const PPTable_Generic_SubTable_Header *sclk_dep_table = - (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usSclkDependencyTableOffset)); - const ATOM_Tonga_Hard_Limit_Table *pHardLimits = - (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usHardLimitTableOffset)); - const PPTable_Generic_SubTable_Header *pcie_table = - (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usPCIETableOffset)); - const ATOM_Tonga_GPIO_Table *gpio_table = - (const ATOM_Tonga_GPIO_Table *)(((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usGPIOTableOffset)); + const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table; + const PPTable_Generic_SubTable_Header *pPowerTuneTable; + const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table; + const PPTable_Generic_SubTable_Header *sclk_dep_table; + const ATOM_Tonga_Hard_Limit_Table *pHardLimits; + const PPTable_Generic_SubTable_Header *pcie_table; + const ATOM_Tonga_GPIO_Table *gpio_table; pp_table_information->vdd_dep_on_sclk = NULL; pp_table_information->vdd_dep_on_mclk = NULL; @@ -818,29 +1216,58 @@ static int init_clock_voltage_dependency( pp_table_information->pcie_table = NULL; pp_table_information->gpio_table = NULL; - if (powerplay_table->usMMDependencyTableOffset != 0) - result = get_mm_clock_voltage_table(hwmgr, - &pp_table_information->mm_dep_table, mm_dependency_table); + if (powerplay_table->usMMDependencyTableOffset != 0) { + result = get_tonga_mm_dependency_table(hwmgr, powerplay_table, + &mm_dependency_table); + if (!result) + result = get_mm_clock_voltage_table(hwmgr, + &pp_table_information->mm_dep_table, + mm_dependency_table); + } - if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0) - result = get_cac_tdp_table(hwmgr, - &pp_table_information->cac_dtp_table, pPowerTuneTable); + if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0) { + result = get_tonga_power_tune_table(hwmgr, powerplay_table, + &pPowerTuneTable); + if (!result) + result = get_cac_tdp_table(hwmgr, + &pp_table_information->cac_dtp_table, + pPowerTuneTable); + } - if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0) - result = get_sclk_voltage_dependency_table(hwmgr, - &pp_table_information->vdd_dep_on_sclk, sclk_dep_table); + if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0) { + result = get_tonga_sclk_dependency_table(hwmgr, powerplay_table, + &sclk_dep_table); + if (!result) + result = get_sclk_voltage_dependency_table(hwmgr, + &pp_table_information->vdd_dep_on_sclk, + sclk_dep_table); + } - if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0) - result = get_mclk_voltage_dependency_table(hwmgr, - &pp_table_information->vdd_dep_on_mclk, mclk_dep_table); + if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0) { + result = get_tonga_mclk_dependency_table(hwmgr, powerplay_table, + &mclk_dep_table); + if (!result) + result = get_mclk_voltage_dependency_table(hwmgr, + &pp_table_information->vdd_dep_on_mclk, + mclk_dep_table); + } - if (result == 0 && powerplay_table->usPCIETableOffset != 0) - result = get_pcie_table(hwmgr, - &pp_table_information->pcie_table, pcie_table); + if (result == 0 && powerplay_table->usPCIETableOffset != 0) { + result = get_tonga_pcie_table(hwmgr, powerplay_table, + &pcie_table); + if (!result) + result = get_pcie_table(hwmgr, + &pp_table_information->pcie_table, pcie_table); + } - if (result == 0 && powerplay_table->usHardLimitTableOffset != 0) - result = get_hard_limits(hwmgr, - &pp_table_information->max_clock_voltage_on_dc, pHardLimits); + if (result == 0 && powerplay_table->usHardLimitTableOffset != 0) { + result = get_tonga_hard_limit_table(hwmgr, powerplay_table, + &pHardLimits); + if (!result) + result = get_hard_limits(hwmgr, + &pp_table_information->max_clock_voltage_on_dc, + pHardLimits); + } hwmgr->dyn_state.max_clock_voltage_on_dc.sclk = pp_table_information->max_clock_voltage_on_dc.sclk; @@ -861,9 +1288,13 @@ static int init_clock_voltage_dependency( result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values, pp_table_information->vdd_dep_on_sclk); - if (!result && gpio_table) - result = get_gpio_table(hwmgr, &pp_table_information->gpio_table, - gpio_table); + if (!result && powerplay_table->usGPIOTableOffset) { + result = get_tonga_gpio_table(hwmgr, powerplay_table, + &gpio_table); + if (!result) + result = get_gpio_table(hwmgr, + &pp_table_information->gpio_table, gpio_table); + } return result; } @@ -908,14 +1339,17 @@ static int init_thermal_controller( ) { const PPTable_Generic_SubTable_Header *fan_table; - ATOM_Tonga_Thermal_Controller *thermal_controller; + const ATOM_Tonga_Thermal_Controller *thermal_controller; + int ret; - thermal_controller = (ATOM_Tonga_Thermal_Controller *) - (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usThermalControllerOffset)); PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset), "Thermal controller table not set!", return -1); + ret = get_tonga_thermal_controller_table(hwmgr, powerplay_table, + &thermal_controller); + if (ret) + return ret; + hwmgr->thermal_controller.ucType = thermal_controller->ucType; hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine; hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress; @@ -943,12 +1377,13 @@ static int init_thermal_controller( return 0; } - fan_table = (const PPTable_Generic_SubTable_Header *) - (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usFanTableOffset)); - PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset), "Fan table not set!", return -1); + + ret = get_tonga_fan_table(hwmgr, powerplay_table, &fan_table); + if (ret) + return ret; + PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId), "Unsupported fan table format!", return -1); @@ -1104,21 +1539,24 @@ static int init_thermal_controller( } /** - * check_powerplay_tables - Private Function used during initialization. - * Inspect the PowerPlay table for obvious signs of corruption. + * get_tonga_state_array - Get the Tonga state array from the PowerPlay table. * @hwmgr: Pointer to the hardware manager. * @powerplay_table: Pointer to the PowerPlay Table. - * Exception: 2 if the powerplay table is incorrect. + * @state_array: Pointer to the returned Tonga state array. + * + * Return: 0 on success, negative error code on failure. */ -static int check_powerplay_tables( - struct pp_hwmgr *hwmgr, - const ATOM_Tonga_POWERPLAYTABLE *powerplay_table - ) +static int get_tonga_state_array(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table, + const ATOM_Tonga_State_Array **state_array) { const ATOM_Tonga_State_Array *state_arrays; + u16 state_array_offset; + size_t state_array_size; + size_t table_size = hwmgr->soft_pp_table_size; - state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usStateArrayOffset)); + PP_ASSERT_WITH_CODE((table_size >= sizeof(*powerplay_table)), + "Invalid PowerPlay Table!", return -1); PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <= powerplay_table->sHeader.ucTableFormatRevision), @@ -1127,12 +1565,34 @@ static int check_powerplay_tables( "State table is not set!", return -1); PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize), "Invalid PowerPlay Table!", return -1); + + state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset); + PP_ASSERT_WITH_CODE((state_array_offset <= + table_size - sizeof(*state_arrays)), + "Invalid PowerPlay Table!", return -1); + + state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) + + state_array_offset); PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries), "Invalid PowerPlay Table!", return -1); + state_array_size = struct_size(state_arrays, entries, state_arrays->ucNumEntries); + PP_ASSERT_WITH_CODE((state_array_size <= table_size - state_array_offset), + "Invalid PowerPlay Table!", return -1); + + *state_array = state_arrays; + return 0; } +static int check_powerplay_tables(struct pp_hwmgr *hwmgr, + const ATOM_Tonga_POWERPLAYTABLE *powerplay_table) +{ + const ATOM_Tonga_State_Array *state_arrays; + + return get_tonga_state_array(hwmgr, powerplay_table, &state_arrays); +} + static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr) { int result = 0; @@ -1236,17 +1696,16 @@ const struct pp_table_func pptable_v1_0_funcs = { int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr) { - ATOM_Tonga_State_Array const *state_arrays; + const ATOM_Tonga_State_Array *state_arrays; const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); + int result; PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1); - PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >= - ATOM_Tonga_TABLE_REVISION_TONGA), - "Incorrect PowerPlay table revision!", return -1); - state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + - le16_to_cpu(pp_table->usStateArrayOffset)); + result = get_tonga_state_array(hwmgr, pp_table, &state_arrays); + PP_ASSERT_WITH_CODE((result == 0), + "Invalid PowerPlay Table State Array.", return result); return (uint32_t)(state_arrays->ucNumEntries); } @@ -1287,13 +1746,15 @@ static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr) { const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); const ATOM_Tonga_VCE_State_Table *vce_state_table; + int ret; if (pp_table == NULL) return 0; - vce_state_table = (void *)pp_table + - le16_to_cpu(pp_table->usVCEStateTableOffset); + ret = get_tonga_vce_state_table(hwmgr, pp_table, &vce_state_table); + if (ret) + return 0; return vce_state_table->ucNumEntries; } @@ -1302,18 +1763,39 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i struct amd_vce_state *vce_state, void **clock_info, uint32_t *flag) { const ATOM_Tonga_VCE_State_Record *vce_state_record; - ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record; + ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record = NULL; + ATOM_Polaris_SCLK_Dependency_Record *polaris_sclk_dep_record = NULL; ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record; ATOM_Tonga_MM_Dependency_Record *mm_dep_record; const ATOM_Tonga_POWERPLAYTABLE *pptable = get_powerplay_table(hwmgr); - const ATOM_Tonga_VCE_State_Table *vce_state_table = (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pptable) - + le16_to_cpu(pptable->usVCEStateTableOffset)); - const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table = (ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long)pptable) - + le16_to_cpu(pptable->usSclkDependencyTableOffset)); - const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = (ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long)pptable) - + le16_to_cpu(pptable->usMclkDependencyTableOffset)); - const ATOM_Tonga_MM_Dependency_Table *mm_dep_table = (ATOM_Tonga_MM_Dependency_Table *)(((unsigned long)pptable) - + le16_to_cpu(pptable->usMMDependencyTableOffset)); + const ATOM_Tonga_VCE_State_Table *vce_state_table; + const PPTable_Generic_SubTable_Header *sclk_dep_table_header; + const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table; + const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table; + const ATOM_Tonga_MM_Dependency_Table *mm_dep_table; + int ret; + + if (!pptable) + return -EINVAL; + + ret = get_tonga_vce_state_table(hwmgr, pptable, &vce_state_table); + if (ret) + return ret; + + ret = get_tonga_sclk_dependency_table(hwmgr, pptable, + &sclk_dep_table_header); + if (ret) + return ret; + sclk_dep_table = (const ATOM_Tonga_SCLK_Dependency_Table *) + sclk_dep_table_header; + + ret = get_tonga_mclk_dependency_table(hwmgr, pptable, &mclk_dep_table); + if (ret) + return ret; + + ret = get_tonga_mm_dependency_table(hwmgr, pptable, &mm_dep_table); + if (ret) + return ret; PP_ASSERT_WITH_CODE((i < vce_state_table->ucNumEntries), "Requested state entry ID is out of range!", @@ -1322,10 +1804,27 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i vce_state_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( ATOM_Tonga_VCE_State_Record, entries, vce_state_table, i); - sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( - ATOM_Tonga_SCLK_Dependency_Record, - entries, sclk_dep_table, - vce_state_record->ucSCLKIndex); + PP_ASSERT_WITH_CODE((vce_state_record->ucSCLKIndex < + sclk_dep_table->ucNumEntries), + "Invalid PowerPlay Table!", return -EINVAL); + PP_ASSERT_WITH_CODE((vce_state_record->ucVCEClockIndex < + mm_dep_table->ucNumEntries), + "Invalid PowerPlay Table!", return -EINVAL); + PP_ASSERT_WITH_CODE((mclk_dep_table->ucNumEntries != 0), + "Invalid PowerPlay Table!", return -EINVAL); + + if (sclk_dep_table_header->ucRevId < 1) + sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( + ATOM_Tonga_SCLK_Dependency_Record, + entries, sclk_dep_table, + vce_state_record->ucSCLKIndex); + else + polaris_sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( + ATOM_Polaris_SCLK_Dependency_Record, + entries, + (ATOM_Polaris_SCLK_Dependency_Table *) + sclk_dep_table_header, + vce_state_record->ucSCLKIndex); mm_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( ATOM_Tonga_MM_Dependency_Record, entries, mm_dep_table, @@ -1334,7 +1833,10 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i vce_state->evclk = le32_to_cpu(mm_dep_record->ulEClk); vce_state->ecclk = le32_to_cpu(mm_dep_record->ulEClk); - vce_state->sclk = le32_to_cpu(sclk_dep_record->ulSclk); + if (sclk_dep_record) + vce_state->sclk = le32_to_cpu(sclk_dep_record->ulSclk); + else + vce_state->sclk = le32_to_cpu(polaris_sclk_dep_record->ulSclk); if (vce_state_record->ucMCLKIndex >= mclk_dep_table->ucNumEntries) mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( @@ -1377,15 +1879,11 @@ int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr, if (pp_table->sHeader.ucTableFormatRevision >= ATOM_Tonga_TABLE_REVISION_TONGA) { - state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + - le16_to_cpu(pp_table->usStateArrayOffset)); - - PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset), - "Invalid PowerPlay Table State Array Offset.", return -1); - PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries), - "Invalid PowerPlay Table State Array.", return -1); - PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), - "Invalid PowerPlay Table State Array Entry.", return -1); + result = get_tonga_state_array(hwmgr, pp_table, &state_arrays); + PP_ASSERT_WITH_CODE((result == 0), + "Invalid PowerPlay Table State Array.", return result); + PP_ASSERT_WITH_CODE((entry_index < state_arrays->ucNumEntries), + "Invalid PowerPlay Table State Array Entry.", return -1); state_entry = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( ATOM_Tonga_State, entries, @@ -1411,4 +1909,3 @@ int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr, return result; } - diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c index bfd8fbb0b49d..56926eec6820 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c @@ -47,26 +47,53 @@ #define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6 +static bool pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset, + size_t size) +{ + size_t table_size = hwmgr->soft_pp_table_size; + + return offset <= table_size && size <= table_size - offset; +} + +static const ATOM_PPLIB_EXTENDEDHEADER * +get_extended_header(struct pp_hwmgr *hwmgr, + const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, + size_t min_size) +{ + const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3; + const ATOM_PPLIB_EXTENDEDHEADER *extended_header; + u16 offset; + + if (le16_to_cpu(powerplay_table->usTableSize) < + sizeof(ATOM_PPLIB_POWERPLAYTABLE3) || + !pp_table_has_space(hwmgr, 0, sizeof(ATOM_PPLIB_POWERPLAYTABLE3))) + return NULL; + + powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; + offset = le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset); + if (!offset || !pp_table_has_space(hwmgr, offset, + sizeof(extended_header->usSize))) + return NULL; + + extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *) + (((unsigned long)powerplay_table) + offset); + if (le16_to_cpu(extended_header->usSize) < min_size || + !pp_table_has_space(hwmgr, offset, min_size)) + return NULL; + + return extended_header; +} + static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) { uint16_t vce_table_offset = 0; + const ATOM_PPLIB_EXTENDEDHEADER *extended_header; - if (le16_to_cpu(powerplay_table->usTableSize) >= - sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { - const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = - (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; - - if (powerplay_table3->usExtendendedHeaderOffset > 0) { - const ATOM_PPLIB_EXTENDEDHEADER *extended_header = - (const ATOM_PPLIB_EXTENDEDHEADER *) - (((unsigned long)powerplay_table3) + - le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); - if (le16_to_cpu(extended_header->usSize) >= - SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) - vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset); - } - } + extended_header = get_extended_header(hwmgr, powerplay_table, + SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2); + if (extended_header) + vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset); return vce_table_offset; } @@ -93,7 +120,14 @@ static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr, if (table_offset > 0) { const VCEClockInfoArray *p = (const VCEClockInfoArray *) (((unsigned long) powerplay_table) + table_offset); - table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo); + size_t size; + + if (!pp_table_has_space(hwmgr, table_offset, sizeof(p->ucNumEntries))) + return 0; + + size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo); + if (pp_table_has_space(hwmgr, table_offset, size)) + table_size = size; } return table_size; @@ -104,10 +138,13 @@ static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr, { uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table); + u16 table_size; - if (table_offset > 0) - return table_offset + get_vce_clock_info_array_size(hwmgr, - powerplay_table); + if (table_offset > 0) { + table_size = get_vce_clock_info_array_size(hwmgr, powerplay_table); + if (table_size) + return table_offset + table_size; + } return 0; } @@ -121,8 +158,15 @@ static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr, if (table_offset > 0) { const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable = (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset); + size_t size; - table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record); + if (!pp_table_has_space(hwmgr, table_offset, sizeof(ptable->numEntries))) + return 0; + + size = sizeof(uint8_t) + + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record); + if (pp_table_has_space(hwmgr, table_offset, size)) + table_size = size; } return table_size; } @@ -130,9 +174,13 @@ static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr, static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) { uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table); + u16 table_size; - if (table_offset > 0) - return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table); + if (table_offset > 0) { + table_size = get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table); + if (table_size) + return table_offset + table_size; + } return 0; } @@ -143,8 +191,12 @@ static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table( { uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table); - if (table_offset > 0) - return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset); + if (table_offset > 0) { + if (pp_table_has_space(hwmgr, table_offset, + sizeof(((ATOM_PPLIB_VCE_State_Table *)0)->numEntries))) + return (const ATOM_PPLIB_VCE_State_Table *) + (((unsigned long)powerplay_table) + table_offset); + } return NULL; } @@ -153,21 +205,13 @@ static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) { uint16_t uvd_table_offset = 0; + const ATOM_PPLIB_EXTENDEDHEADER *extended_header; + + extended_header = get_extended_header(hwmgr, powerplay_table, + SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3); + if (extended_header) + uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset); - if (le16_to_cpu(powerplay_table->usTableSize) >= - sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { - const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = - (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; - if (powerplay_table3->usExtendendedHeaderOffset > 0) { - const ATOM_PPLIB_EXTENDEDHEADER *extended_header = - (const ATOM_PPLIB_EXTENDEDHEADER *) - (((unsigned long)powerplay_table3) + - le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); - if (le16_to_cpu(extended_header->usSize) >= - SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) - uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset); - } - } return uvd_table_offset; } @@ -193,8 +237,14 @@ static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr, const UVDClockInfoArray *p = (const UVDClockInfoArray *) (((unsigned long) powerplay_table) + table_offset); - table_size = sizeof(UCHAR) + - p->ucNumEntries * sizeof(UVDClockInfo); + size_t size; + + if (!pp_table_has_space(hwmgr, table_offset, sizeof(p->ucNumEntries))) + return 0; + + size = sizeof(UCHAR) + p->ucNumEntries * sizeof(UVDClockInfo); + if (pp_table_has_space(hwmgr, table_offset, size)) + table_size = size; } return table_size; @@ -206,10 +256,13 @@ static uint16_t get_uvd_clock_voltage_limit_table_offset( { uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table); + u16 table_size; - if (table_offset > 0) - return table_offset + - get_uvd_clock_info_array_size(hwmgr, powerplay_table); + if (table_offset > 0) { + table_size = get_uvd_clock_info_array_size(hwmgr, powerplay_table); + if (table_size) + return table_offset + table_size; + } return 0; } @@ -218,21 +271,12 @@ static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) { uint16_t samu_table_offset = 0; + const ATOM_PPLIB_EXTENDEDHEADER *extended_header; - if (le16_to_cpu(powerplay_table->usTableSize) >= - sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { - const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = - (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; - if (powerplay_table3->usExtendendedHeaderOffset > 0) { - const ATOM_PPLIB_EXTENDEDHEADER *extended_header = - (const ATOM_PPLIB_EXTENDEDHEADER *) - (((unsigned long)powerplay_table3) + - le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); - if (le16_to_cpu(extended_header->usSize) >= - SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) - samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset); - } - } + extended_header = get_extended_header(hwmgr, powerplay_table, + SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4); + if (extended_header) + samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset); return samu_table_offset; } @@ -254,21 +298,12 @@ static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) { uint16_t acp_table_offset = 0; + const ATOM_PPLIB_EXTENDEDHEADER *extended_header; - if (le16_to_cpu(powerplay_table->usTableSize) >= - sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { - const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = - (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; - if (powerplay_table3->usExtendendedHeaderOffset > 0) { - const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader = - (const ATOM_PPLIB_EXTENDEDHEADER *) - (((unsigned long)powerplay_table3) + - le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); - if (le16_to_cpu(pExtendedHeader->usSize) >= - SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) - acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset); - } - } + extended_header = get_extended_header(hwmgr, powerplay_table, + SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6); + if (extended_header) + acp_table_offset = le16_to_cpu(extended_header->usACPTableOffset); return acp_table_offset; } @@ -290,21 +325,12 @@ static uint16_t get_cacp_tdp_table_offset( const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) { uint16_t cacTdpTableOffset = 0; + const ATOM_PPLIB_EXTENDEDHEADER *extended_header; - if (le16_to_cpu(powerplay_table->usTableSize) >= - sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { - const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = - (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; - if (powerplay_table3->usExtendendedHeaderOffset > 0) { - const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader = - (const ATOM_PPLIB_EXTENDEDHEADER *) - (((unsigned long)powerplay_table3) + - le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); - if (le16_to_cpu(pExtendedHeader->usSize) >= - SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) - cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset); - } - } + extended_header = get_extended_header(hwmgr, powerplay_table, + SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7); + if (extended_header) + cacTdpTableOffset = le16_to_cpu(extended_header->usPowerTuneTableOffset); return cacTdpTableOffset; } @@ -341,22 +367,13 @@ static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) { uint16_t sclk_vdd_gfx_table_offset = 0; + const ATOM_PPLIB_EXTENDEDHEADER *extended_header; - if (le16_to_cpu(powerplay_table->usTableSize) >= - sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { - const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = - (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; - if (powerplay_table3->usExtendendedHeaderOffset > 0) { - const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader = - (const ATOM_PPLIB_EXTENDEDHEADER *) - (((unsigned long)powerplay_table3) + - le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); - if (le16_to_cpu(pExtendedHeader->usSize) >= - SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8) - sclk_vdd_gfx_table_offset = - le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset); - } - } + extended_header = get_extended_header(hwmgr, powerplay_table, + SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8); + if (extended_header) + sclk_vdd_gfx_table_offset = + le16_to_cpu(extended_header->usSclkVddgfxTableOffset); return sclk_vdd_gfx_table_offset; } @@ -769,20 +786,37 @@ static ULONG size_of_entry_v2(ULONG num_dpm_levels) } static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2( + struct pp_hwmgr *hwmgr, const StateArray * pstate_arrays, + u16 state_array_offset, ULONG entry_index) { ULONG i; const ATOM_PPLIB_STATE_V2 *pstate; + size_t entry_offset; + size_t entry_size; + if (entry_index >= pstate_arrays->ucNumEntries) + return NULL; + + entry_offset = state_array_offset + sizeof(pstate_arrays->ucNumEntries); pstate = pstate_arrays->states; - if (entry_index <= pstate_arrays->ucNumEntries) { - for (i = 0; i < entry_index; i++) - pstate = (ATOM_PPLIB_STATE_V2 *)( - (unsigned long)pstate + - size_of_entry_v2(pstate->ucNumDPMLevels)); + for (i = 0; i <= entry_index; i++) { + if (!pp_table_has_space(hwmgr, entry_offset, sizeof(*pstate))) + return NULL; + + entry_size = size_of_entry_v2(pstate->ucNumDPMLevels); + if (!pp_table_has_space(hwmgr, entry_offset, entry_size)) + return NULL; + + if (i == entry_index) + return pstate; + + entry_offset += entry_size; + pstate = (ATOM_PPLIB_STATE_V2 *)((unsigned long)pstate + entry_size); } - return pstate; + + return NULL; } static const unsigned char soft_dummy_pp_table[] = { @@ -850,6 +884,8 @@ int pp_tables_get_response_times(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE(NULL != powerplay_tab, "Missing PowerPlay Table!", return -EINVAL); + PP_ASSERT_WITH_CODE(pp_table_has_space(hwmgr, 0, sizeof(*powerplay_tab)), + "Invalid PowerPlay Table!", return -EINVAL); *vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime); *bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime); @@ -862,13 +898,21 @@ int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr, { const StateArray *pstate_arrays; const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr); + u16 state_array_offset; if (powerplay_table == NULL) return -1; + if (!pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table))) + return -1; if (powerplay_table->sHeader.ucTableFormatRevision >= 6) { + state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset); + if (!pp_table_has_space(hwmgr, state_array_offset, + sizeof(pstate_arrays->ucNumEntries))) + return -1; + pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usStateArrayOffset)); + state_array_offset); *num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries); } else @@ -895,49 +939,128 @@ int pp_tables_get_entry(struct pp_hwmgr *hwmgr, const NonClockInfoArray *pnon_clock_arrays; const ATOM_PPLIB_STATE *pstate_entry; + u16 state_array_offset; + u16 clock_info_array_offset; + u16 non_clock_info_array_offset; + size_t clock_info_offset; + size_t non_clock_info_offset; + size_t state_entry_offset; if (powerplay_table == NULL) return -1; + if (!pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table))) + return -1; ps->classification.bios_index = entry_index; if (powerplay_table->sHeader.ucTableFormatRevision >= 6) { - pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usStateArrayOffset)); - - if (entry_index > pstate_arrays->ucNumEntries) + state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset); + if (!pp_table_has_space(hwmgr, state_array_offset, + sizeof(pstate_arrays->ucNumEntries))) + return -1; + + pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) + + state_array_offset); + + if (entry_index >= pstate_arrays->ucNumEntries) + return -1; + + pstate_entry_v2 = get_state_entry_v2(hwmgr, pstate_arrays, + state_array_offset, + entry_index); + if (!pstate_entry_v2) + return -1; + + clock_info_array_offset = + le16_to_cpu(powerplay_table->usClockInfoArrayOffset); + if (!pp_table_has_space(hwmgr, clock_info_array_offset, + sizeof(*pclock_arrays))) return -1; - pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index); pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usClockInfoArrayOffset)); + clock_info_array_offset); + if (!pclock_arrays->ucEntrySize) + return -1; + + non_clock_info_array_offset = + le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset); + if (!pp_table_has_space(hwmgr, non_clock_info_array_offset, + sizeof(*pnon_clock_arrays))) + return -1; pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset)); + non_clock_info_array_offset); + if (!pnon_clock_arrays->ucEntrySize || + pnon_clock_arrays->ucEntrySize < ATOM_PPLIB_NONCLOCKINFO_VER1 || + (pnon_clock_arrays->ucEntrySize > ATOM_PPLIB_NONCLOCKINFO_VER1 && + pnon_clock_arrays->ucEntrySize < ATOM_PPLIB_NONCLOCKINFO_VER2) || + pstate_entry_v2->nonClockInfoIndex >= pnon_clock_arrays->ucNumEntries) + return -1; + non_clock_info_offset = non_clock_info_array_offset + + offsetof(NonClockInfoArray, nonClockInfo) + + pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize; + if (!pp_table_has_space(hwmgr, non_clock_info_offset, + pnon_clock_arrays->ucEntrySize)) + return -1; pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) + (pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize)); result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info); for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) { - const void *pclock_info = (const void *)( - (unsigned long)(pclock_arrays->clockInfo) + - (pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize)); + const void *pclock_info; + + if (pstate_entry_v2->clockInfoIndex[i] >= + pclock_arrays->ucNumEntries) + return -1; + + clock_info_offset = clock_info_array_offset + + offsetof(ClockInfoArray, clockInfo) + + pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize; + if (!pp_table_has_space(hwmgr, clock_info_offset, + pclock_arrays->ucEntrySize)) + return -1; + + pclock_info = (const void *) + ((unsigned long)(pclock_arrays->clockInfo) + + (pstate_entry_v2->clockInfoIndex[i] * + pclock_arrays->ucEntrySize)); res = func(hwmgr, &ps->hardware, i, pclock_info); if ((0 == result) && (0 != res)) result = res; } } else { - if (entry_index > powerplay_table->ucNumStates) + if (entry_index >= powerplay_table->ucNumStates || + !powerplay_table->ucStateEntrySize || + !powerplay_table->ucNonClockSize || + powerplay_table->ucNonClockSize < ATOM_PPLIB_NONCLOCKINFO_VER1 || + (powerplay_table->ucNonClockSize > ATOM_PPLIB_NONCLOCKINFO_VER1 && + powerplay_table->ucNonClockSize < ATOM_PPLIB_NONCLOCKINFO_VER2) || + !powerplay_table->ucClockInfoSize) + return -1; + + state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset); + state_entry_offset = state_array_offset + + entry_index * powerplay_table->ucStateEntrySize; + if (!pp_table_has_space(hwmgr, state_entry_offset, + powerplay_table->ucStateEntrySize)) return -1; pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table + - le16_to_cpu(powerplay_table->usStateArrayOffset) + + state_array_offset + entry_index * powerplay_table->ucStateEntrySize); + non_clock_info_array_offset = + le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset); + non_clock_info_offset = non_clock_info_array_offset + + pstate_entry->ucNonClockStateIndex * powerplay_table->ucNonClockSize; + if (!pp_table_has_space(hwmgr, non_clock_info_offset, + powerplay_table->ucNonClockSize)) + return -1; + pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table + - le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) + + non_clock_info_array_offset + pstate_entry->ucNonClockStateIndex * powerplay_table->ucNonClockSize); @@ -946,12 +1069,23 @@ int pp_tables_get_entry(struct pp_hwmgr *hwmgr, pnon_clock_info); for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) { - const void *pclock_info = (const void *)((unsigned long)powerplay_table + - le16_to_cpu(powerplay_table->usClockInfoArrayOffset) + + const void *pclock_info; + + clock_info_array_offset = + le16_to_cpu(powerplay_table->usClockInfoArrayOffset); + clock_info_offset = clock_info_array_offset + + pstate_entry->ucClockStateIndices[i] * + powerplay_table->ucClockInfoSize; + if (!pp_table_has_space(hwmgr, clock_info_offset, + powerplay_table->ucClockInfoSize)) + return -1; + + pclock_info = (const void *)((unsigned long)powerplay_table + + clock_info_array_offset + pstate_entry->ucClockStateIndices[i] * powerplay_table->ucClockInfoSize); - int res = func(hwmgr, &ps->hardware, i, pclock_info); + res = func(hwmgr, &ps->hardware, i, pclock_info); if ((0 == result) && (0 != res)) result = res; @@ -1661,21 +1795,70 @@ static int get_vce_state_table_entry(struct pp_hwmgr *hwmgr, unsigned long *flag) { const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr); + const ATOM_PPLIB_VCE_State_Table *vce_state_table; + const ATOM_PPLIB_VCE_State_Record *record; + const VCEClockInfoArray *vce_clock_info_array; + const VCEClockInfo *vce_clock_info; + const ClockInfoArray *clock_arrays; + u16 vce_state_table_offset; + u16 vce_clock_info_array_offset; + u16 clock_info_array_offset; + unsigned long clockInfoIndex; + size_t record_offset; + size_t vce_clock_info_offset; + size_t clock_info_offset; - const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table); + if (!powerplay_table || !pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table))) + return -1; - unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table); + vce_state_table_offset = get_vce_state_table_offset(hwmgr, powerplay_table); + vce_state_table = get_vce_state_table(hwmgr, powerplay_table); + if (!vce_state_table || i >= vce_state_table->numEntries) + return -1; - const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset); + record_offset = vce_state_table_offset + + offsetof(ATOM_PPLIB_VCE_State_Table, entries) + + i * sizeof(*record); + if (!pp_table_has_space(hwmgr, record_offset, sizeof(*record))) + return -1; - const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usClockInfoArrayOffset)); + record = &vce_state_table->entries[i]; - const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i]; + vce_clock_info_array_offset = + get_vce_clock_info_array_offset(hwmgr, powerplay_table); + if (!pp_table_has_space(hwmgr, vce_clock_info_array_offset, + sizeof(vce_clock_info_array->ucNumEntries))) + return -1; - const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex]; + vce_clock_info_array = (const VCEClockInfoArray *) + (((unsigned long)powerplay_table) + vce_clock_info_array_offset); + if (record->ucVCEClockInfoIndex >= vce_clock_info_array->ucNumEntries) + return -1; - unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F; + vce_clock_info_offset = vce_clock_info_array_offset + + offsetof(VCEClockInfoArray, entries) + + record->ucVCEClockInfoIndex * sizeof(*vce_clock_info); + if (!pp_table_has_space(hwmgr, vce_clock_info_offset, sizeof(*vce_clock_info))) + return -1; + + vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex]; + + clock_info_array_offset = le16_to_cpu(powerplay_table->usClockInfoArrayOffset); + if (!pp_table_has_space(hwmgr, clock_info_array_offset, + sizeof(*clock_arrays))) + return -1; + + clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + + clock_info_array_offset); + clockInfoIndex = record->ucClockInfoIndex & 0x3F; + if (!clock_arrays->ucEntrySize || clockInfoIndex >= clock_arrays->ucNumEntries) + return -1; + + clock_info_offset = clock_info_array_offset + + offsetof(ClockInfoArray, clockInfo) + + clockInfoIndex * clock_arrays->ucEntrySize; + if (!pp_table_has_space(hwmgr, clock_info_offset, clock_arrays->ucEntrySize)) + return -1; *flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX); @@ -1699,6 +1882,10 @@ static int pp_tables_initialize(struct pp_hwmgr *hwmgr) hwmgr->need_pp_table_upload = true; powerplay_table = get_powerplay_table(hwmgr); + PP_ASSERT_WITH_CODE((powerplay_table), + "Missing PowerPlay Table!", return -1); + PP_ASSERT_WITH_CODE(pp_table_has_space(hwmgr, 0, sizeof(*powerplay_table)), + "Invalid PowerPlay Table!", return -1); result = init_powerplay_tables(hwmgr, powerplay_table); @@ -1801,4 +1988,3 @@ const struct pp_table_func pptable_funcs = { .pptable_get_vce_state_table_entry = get_vce_state_table_entry, }; - diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c index 95bf187f02a5..1f1bb274685a 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c @@ -2216,12 +2216,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table( if (data->vdd_gfx_control == SMU7_VOLTAGE_CONTROL_BY_SVID2) { for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) { voltage_id = sclk_table->entries[entry_id].vddInd; + if (voltage_id >= table_info->vddgfx_lookup_table->count) { + pr_err("amdgpu: sclk[%u] vddgfx index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddgfx_lookup_table->count); + return -EINVAL; + } sclk_table->entries[entry_id].vddgfx = table_info->vddgfx_lookup_table->entries[voltage_id].us_vdd; } } else { for (entry_id = 0; entry_id < sclk_table->count; ++entry_id) { voltage_id = sclk_table->entries[entry_id].vddInd; + if (voltage_id >= table_info->vddc_lookup_table->count) { + pr_err("amdgpu: sclk[%u] vddc index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddc_lookup_table->count); + return -EINVAL; + } sclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; } @@ -2229,12 +2241,24 @@ static int smu7_patch_voltage_dependency_tables_with_lookup_table( for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) { voltage_id = mclk_table->entries[entry_id].vddInd; + if (voltage_id >= table_info->vddc_lookup_table->count) { + pr_err("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddc_lookup_table->count); + return -EINVAL; + } mclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; } for (entry_id = 0; entry_id < mm_table->count; ++entry_id) { voltage_id = mm_table->entries[entry_id].vddcInd; + if (voltage_id >= table_info->vddc_lookup_table->count) { + pr_err("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddc_lookup_table->count); + return -EINVAL; + } mm_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; } @@ -5648,23 +5672,29 @@ static int smu7_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, } for (i = 0; i < size; i += 3) { - if (i + 3 > size || input[i] >= podn_dpm_table_in_backend->num_of_pl) { - pr_info("invalid clock voltage input \n"); - return 0; - } - input_level = input[i]; - input_clk = input[i+1] * 100; - input_vol = input[i+2]; - - if (smu7_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) { - podn_dpm_table_in_backend->entries[input_level].clock = input_clk; - podn_vdd_dep_in_backend->entries[input_level].clk = input_clk; - podn_dpm_table_in_backend->entries[input_level].vddc = input_vol; - podn_vdd_dep_in_backend->entries[input_level].vddc = input_vol; - podn_vdd_dep_in_backend->entries[input_level].vddgfx = input_vol; - } else { + if (i + 3 > size) { + pr_info("truncated clock/voltage input\n"); return -EINVAL; } + if (input[i] < 0 || input[i] >= podn_dpm_table_in_backend->num_of_pl) { + pr_info("invalid clock/voltage level\n"); + return -EINVAL; + } + input_clk = input[i + 1] * 100; + input_vol = input[i + 2]; + if (!smu7_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) + return -EINVAL; + } + + for (i = 0; i < size; i += 3) { + input_level = input[i]; + input_clk = input[i + 1] * 100; + input_vol = input[i + 2]; + podn_dpm_table_in_backend->entries[input_level].clock = input_clk; + podn_vdd_dep_in_backend->entries[input_level].clk = input_clk; + podn_dpm_table_in_backend->entries[input_level].vddc = input_vol; + podn_vdd_dep_in_backend->entries[input_level].vddc = input_vol; + podn_vdd_dep_in_backend->entries[input_level].vddgfx = input_vol; } return 0; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c index 4b92b52aba2b..0e237feb1629 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c @@ -685,10 +685,18 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table( case 3: vdt = table_info->vdd_dep_on_pixclk; break; case 4: vdt = table_info->vdd_dep_on_dispclk; break; case 5: vdt = table_info->vdd_dep_on_phyclk; break; + default: + continue; } for (entry_id = 0; entry_id < vdt->count; entry_id++) { voltage_id = vdt->entries[entry_id].vddInd; + if (voltage_id >= table_info->vddc_lookup_table->count) { + pr_err("amdgpu: clk_dep[%u][%u] vddc index %u out of bounds (%u)\n", + i, entry_id, voltage_id, + table_info->vddc_lookup_table->count); + return -EINVAL; + } vdt->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; } @@ -696,23 +704,48 @@ static int vega10_patch_voltage_dependency_tables_with_lookup_table( for (entry_id = 0; entry_id < mm_table->count; ++entry_id) { voltage_id = mm_table->entries[entry_id].vddcInd; + if (voltage_id >= table_info->vddc_lookup_table->count) { + pr_err("amdgpu: mm[%u] vddc index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddc_lookup_table->count); + return -EINVAL; + } mm_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; } for (entry_id = 0; entry_id < mclk_table->count; ++entry_id) { voltage_id = mclk_table->entries[entry_id].vddInd; + if (voltage_id >= table_info->vddc_lookup_table->count) { + pr_err("amdgpu: mclk[%u] vddc index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddc_lookup_table->count); + return -EINVAL; + } mclk_table->entries[entry_id].vddc = table_info->vddc_lookup_table->entries[voltage_id].us_vdd; + voltage_id = mclk_table->entries[entry_id].vddciInd; + if (voltage_id >= table_info->vddci_lookup_table->count) { + pr_err("amdgpu: mclk[%u] vddci index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddci_lookup_table->count); + return -EINVAL; + } mclk_table->entries[entry_id].vddci = table_info->vddci_lookup_table->entries[voltage_id].us_vdd; + voltage_id = mclk_table->entries[entry_id].mvddInd; + if (voltage_id >= table_info->vddmem_lookup_table->count) { + pr_err("amdgpu: mclk[%u] vddmem index %u out of bounds (%u)\n", + entry_id, voltage_id, + table_info->vddmem_lookup_table->count); + return -EINVAL; + } mclk_table->entries[entry_id].mvdd = table_info->vddmem_lookup_table->entries[voltage_id].us_vdd; } - return 0; } @@ -5215,6 +5248,11 @@ static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui uint8_t min_active_level; uint32_t power_profile_mode = input[size]; + if (power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { + pr_err("Invalid power profile mode %u\n", power_profile_mode); + return -EINVAL; + } + if (power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { if (size != 0 && size != 4) return -EINVAL; @@ -5230,6 +5268,10 @@ static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui return -EINVAL; } + if ((input[0] & ~0xFF) || (input[1] & ~0xFF) || + (input[2] & ~0xFF) || (input[3] & ~0xFF)) + return -EINVAL; + data->custom_profile_mode[0] = busy_set_point = input[0]; data->custom_profile_mode[1] = FPS = input[1]; data->custom_profile_mode[2] = use_rlc_busy = input[2]; @@ -5454,11 +5496,9 @@ static int vega10_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, if (PP_OD_EDIT_SCLK_VDDC_TABLE == type) { dpm_table = &data->dpm_table.gfx_table; podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_sclk; - data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; } else if (PP_OD_EDIT_MCLK_VDDC_TABLE == type) { dpm_table = &data->dpm_table.mem_table; podn_vdd_dep_table = &data->odn_dpm_table.vdd_dep_on_mclk; - data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; } else if (PP_OD_RESTORE_DEFAULT_TABLE == type) { memcpy(&(data->dpm_table), &(data->golden_dpm_table), sizeof(struct vega10_dpm_table)); vega10_odn_initial_default_setting(hwmgr); @@ -5476,21 +5516,32 @@ static int vega10_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, } for (i = 0; i < size; i += 3) { - if (i + 3 > size || input[i] >= podn_vdd_dep_table->count) { - pr_info("invalid clock voltage input\n"); - return 0; - } - input_level = input[i]; - input_clk = input[i+1] * 100; - input_vol = input[i+2]; - - if (vega10_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) { - dpm_table->dpm_levels[input_level].value = input_clk; - podn_vdd_dep_table->entries[input_level].clk = input_clk; - podn_vdd_dep_table->entries[input_level].vddc = input_vol; - } else { + if (i + 3 > size) { + pr_info("truncated clock/voltage input\n"); return -EINVAL; } + if (input[i] < 0 || input[i] >= podn_vdd_dep_table->count) { + pr_info("invalid clock/voltage level\n"); + return -EINVAL; + } + input_clk = input[i + 1] * 100; + input_vol = input[i + 2]; + if (!vega10_check_clk_voltage_valid(hwmgr, type, input_clk, input_vol)) + return -EINVAL; + } + + if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) + data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_SCLK; + else + data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_MCLK; + + for (i = 0; i < size; i += 3) { + input_level = input[i]; + input_clk = input[i + 1] * 100; + input_vol = input[i + 2]; + dpm_table->dpm_levels[input_level].value = input_clk; + podn_vdd_dep_table->entries[input_level].clk = input_clk; + podn_vdd_dep_table->entries[input_level].vddc = input_vol; } vega10_odn_update_soc_table(hwmgr, type); return 0; diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c index 052d139584fd..62b1e068f90d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c @@ -63,14 +63,57 @@ static const void *get_powerplay_table(struct pp_hwmgr *hwmgr) return table_address; } -static int check_powerplay_tables( - struct pp_hwmgr *hwmgr, - const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) +static bool vega10_pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset, + size_t size) +{ + size_t table_size = hwmgr->soft_pp_table_size; + + return offset <= table_size && size <= table_size - offset; +} + +static int get_vega10_subtable(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + u16 table_offset, size_t table_size, const void **table) +{ + PP_ASSERT_WITH_CODE((table_offset != 0), + "Invalid PowerPlay Table!", return -1); + PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *table = (const void *)(((unsigned long)powerplay_table) + table_offset); + + return 0; +} + +static int validate_vega10_table_entries(struct pp_hwmgr *hwmgr, + u16 table_offset, size_t entries_offset, + u8 num_entries, size_t entry_size) +{ + size_t table_size; + + PP_ASSERT_WITH_CODE((num_entries != 0), + "Invalid PowerPlay Table!", return -1); + + table_size = entries_offset + num_entries * entry_size; + PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + return 0; +} + +static int get_vega10_state_array(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const ATOM_Vega10_State_Array **state_array) { const ATOM_Vega10_State_Array *state_arrays; + u16 state_array_offset; + size_t state_array_size; + size_t table_size = hwmgr->soft_pp_table_size; - state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usStateArrayOffset)); + PP_ASSERT_WITH_CODE((table_size >= sizeof(*powerplay_table)), + "Invalid PowerPlay Table!", return -1); PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >= ATOM_Vega10_TABLE_REVISION_VEGA10), @@ -79,12 +122,321 @@ static int check_powerplay_tables( "State table is not set!", return -1); PP_ASSERT_WITH_CODE(powerplay_table->sHeader.structuresize > 0, "Invalid PowerPlay Table!", return -1); + + state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset); + PP_ASSERT_WITH_CODE((state_array_offset <= + table_size - sizeof(*state_arrays)), + "Invalid PowerPlay Table!", return -1); + + state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) + + state_array_offset); PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, "Invalid PowerPlay Table!", return -1); + state_array_size = struct_size(state_arrays, states, state_arrays->ucNumEntries); + PP_ASSERT_WITH_CODE((state_array_size <= table_size - state_array_offset), + "Invalid PowerPlay Table!", return -1); + + *state_array = state_arrays; + return 0; } +static int get_vega10_gfxclk_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const ATOM_Vega10_GFXCLK_Dependency_Table **gfxclk_dep_table) +{ + const ATOM_Vega10_GFXCLK_Dependency_Table *table; + u16 table_offset; + size_t table_size; + size_t entry_size; + + table_offset = le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset); + if (!table_offset) + return -EINVAL; + + PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset, + sizeof(*table))), + "Invalid PowerPlay Table!", return -1); + + table = (const ATOM_Vega10_GFXCLK_Dependency_Table *) + (((unsigned long)powerplay_table) + table_offset); + PP_ASSERT_WITH_CODE((table->ucNumEntries != 0), + "Invalid PowerPlay Table!", return -1); + + if (table->ucRevId == 0) + entry_size = sizeof(ATOM_Vega10_GFXCLK_Dependency_Record); + else if (table->ucRevId == 1) + entry_size = sizeof(ATOM_Vega10_GFXCLK_Dependency_Record_V2); + else + PP_ASSERT_WITH_CODE(false, + "Unsupported GFXClockDependencyTable Revision!", + return -EINVAL); + + table_size = offsetof(ATOM_Vega10_GFXCLK_Dependency_Table, entries) + + table->ucNumEntries * entry_size; + PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *gfxclk_dep_table = table; + + return 0; +} + +static int get_vega10_clk_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + u16 table_offset, + const ATOM_Vega10_SOCCLK_Dependency_Table **clk_dep_table) +{ + const ATOM_Vega10_SOCCLK_Dependency_Table *table; + int ret; + + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_vega10_table_entries(hwmgr, table_offset, + offsetof(ATOM_Vega10_SOCCLK_Dependency_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Vega10_CLK_Dependency_Record)); + if (ret) + return ret; + + *clk_dep_table = table; + + return 0; +} + +static int get_vega10_mclk_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const ATOM_Vega10_MCLK_Dependency_Table **mclk_dep_table) +{ + const ATOM_Vega10_MCLK_Dependency_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usMclkDependencyTableOffset); + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_vega10_table_entries(hwmgr, table_offset, + offsetof(ATOM_Vega10_MCLK_Dependency_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Vega10_MCLK_Dependency_Record)); + if (ret) + return ret; + + *mclk_dep_table = table; + + return 0; +} + +static int get_vega10_mm_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const ATOM_Vega10_MM_Dependency_Table **mm_dep_table) +{ + const ATOM_Vega10_MM_Dependency_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usMMDependencyTableOffset); + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_vega10_table_entries(hwmgr, table_offset, + offsetof(ATOM_Vega10_MM_Dependency_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Vega10_MM_Dependency_Record)); + if (ret) + return ret; + + *mm_dep_table = table; + + return 0; +} + +static int get_vega10_pcie_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const Vega10_PPTable_Generic_SubTable_Header **pcie_table) +{ + const ATOM_Vega10_PCIE_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usPCIETableOffset); + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + if (!table->ucNumEntries) { + *pcie_table = (const Vega10_PPTable_Generic_SubTable_Header *)table; + return 0; + } + + ret = validate_vega10_table_entries(hwmgr, table_offset, + offsetof(ATOM_Vega10_PCIE_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Vega10_PCIE_Record)); + if (ret) + return ret; + + *pcie_table = (const Vega10_PPTable_Generic_SubTable_Header *)table; + + return 0; +} + +static int get_vega10_hard_limit_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const ATOM_Vega10_Hard_Limit_Table **hard_limit_table) +{ + const ATOM_Vega10_Hard_Limit_Table *table; + u16 table_offset; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usHardLimitTableOffset); + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + ret = validate_vega10_table_entries(hwmgr, table_offset, + offsetof(ATOM_Vega10_Hard_Limit_Table, + entries), + table->ucNumEntries, + sizeof(ATOM_Vega10_Hard_Limit_Record)); + if (ret) + return ret; + + *hard_limit_table = table; + + return 0; +} + +static int get_vega10_thermal_controller_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const ATOM_Vega10_Thermal_Controller **thermal_controller) +{ + u16 table_offset; + + table_offset = le16_to_cpu(powerplay_table->usThermalControllerOffset); + + return get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(**thermal_controller), + (const void **)thermal_controller); +} + +static int get_vega10_fan_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const Vega10_PPTable_Generic_SubTable_Header **fan_table) +{ + const Vega10_PPTable_Generic_SubTable_Header *header; + u16 table_offset; + size_t table_size; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usFanTableOffset); + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*header), (const void **)&header); + if (ret) + return ret; + + if (header->ucRevId == 10) + table_size = sizeof(ATOM_Vega10_Fan_Table); + else if (header->ucRevId == 0xb) + table_size = sizeof(ATOM_Vega10_Fan_Table_V2); + else if (header->ucRevId > 0xb) + table_size = sizeof(ATOM_Vega10_Fan_Table_V3); + else + table_size = sizeof(*header); + + PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *fan_table = header; + + return 0; +} + +static int get_vega10_power_tune_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + const Vega10_PPTable_Generic_SubTable_Header **power_tune_table) +{ + const Vega10_PPTable_Generic_SubTable_Header *header; + u16 table_offset; + size_t table_size; + int ret; + + table_offset = le16_to_cpu(powerplay_table->usPowerTuneTableOffset); + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*header), (const void **)&header); + if (ret) + return ret; + + if (header->ucRevId == 5) + table_size = sizeof(ATOM_Vega10_PowerTune_Table); + else if (header->ucRevId == 6) + table_size = sizeof(ATOM_Vega10_PowerTune_Table_V2); + else + table_size = sizeof(ATOM_Vega10_PowerTune_Table_V3); + + PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *power_tune_table = header; + + return 0; +} + +static int get_vega10_voltage_lookup_table(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table, + u16 table_offset, uint32_t max_levels, + const ATOM_Vega10_Voltage_Lookup_Table **lookup_table) +{ + const ATOM_Vega10_Voltage_Lookup_Table *table; + size_t table_size; + int ret; + + ret = get_vega10_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (ret) + return ret; + + PP_ASSERT_WITH_CODE((table->ucNumEntries != 0 && + table->ucNumEntries <= max_levels), + "Invalid PowerPlay Table!", return -1); + + table_size = offsetof(ATOM_Vega10_Voltage_Lookup_Table, entries) + + table->ucNumEntries * sizeof(ATOM_Vega10_Voltage_Lookup_Record); + PP_ASSERT_WITH_CODE((vega10_pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + *lookup_table = table; + + return 0; +} + +static int check_powerplay_tables(struct pp_hwmgr *hwmgr, + const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) +{ + const ATOM_Vega10_State_Array *state_arrays; + + return get_vega10_state_array(hwmgr, powerplay_table, &state_arrays); +} + static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps) { set_hw_cap( @@ -124,14 +476,16 @@ static int init_thermal_controller( const ATOM_Vega10_Fan_Table *fan_table_v1; const ATOM_Vega10_Fan_Table_V2 *fan_table_v2; const ATOM_Vega10_Fan_Table_V3 *fan_table_v3; - - thermal_controller = (ATOM_Vega10_Thermal_Controller *) - (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usThermalControllerOffset)); + int ret; PP_ASSERT_WITH_CODE((powerplay_table->usThermalControllerOffset != 0), "Thermal controller table not set!", return -EINVAL); + ret = get_vega10_thermal_controller_table(hwmgr, powerplay_table, + &thermal_controller); + if (ret) + return ret; + hwmgr->thermal_controller.ucType = thermal_controller->ucType; hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine; hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress; @@ -160,9 +514,9 @@ static int init_thermal_controller( if (!powerplay_table->usFanTableOffset) return 0; - header = (const Vega10_PPTable_Generic_SubTable_Header *) - (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usFanTableOffset)); + ret = get_vega10_fan_table(hwmgr, powerplay_table, &header); + if (ret) + return ret; if (header->ucRevId == 10) { fan_table_v1 = (ATOM_Vega10_Fan_Table *)header; @@ -307,12 +661,15 @@ static int init_over_drive_limits( struct pp_hwmgr *hwmgr, const ATOM_Vega10_POWERPLAYTABLE *powerplay_table) { - const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table = - (const ATOM_Vega10_GFXCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset)); + const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table; bool is_acg_enabled = false; ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2; + int ret; + + ret = get_vega10_gfxclk_dependency_table(hwmgr, powerplay_table, + &gfxclk_dep_table); + if (ret) + return ret; if (gfxclk_dep_table->ucRevId == 1) { patom_record_v2 = @@ -344,20 +701,28 @@ static int get_mm_clock_voltage_table( const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table) { uint32_t i; + uint32_t num_entries; const ATOM_Vega10_MM_Dependency_Record *mm_dependency_record; phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table; PP_ASSERT_WITH_CODE((mm_dependency_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - mm_table = kzalloc_flex(*mm_table, entries, - mm_dependency_table->ucNumEntries); + num_entries = min_t(uint32_t, mm_dependency_table->ucNumEntries, + pp_entries_max(hwmgr, mm_dependency_table, + sizeof(*mm_dependency_table), + sizeof(ATOM_Vega10_MM_Dependency_Record))); + if (num_entries < mm_dependency_table->ucNumEntries) + pr_warn("amdgpu: Vega10 MM dependency table: clamping ucNumEntries %u -> %u\n", + mm_dependency_table->ucNumEntries, num_entries); + + mm_table = kzalloc_flex(*mm_table, entries, num_entries); if (!mm_table) return -ENOMEM; - mm_table->count = mm_dependency_table->ucNumEntries; + mm_table->count = num_entries; - for (i = 0; i < mm_dependency_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { mm_dependency_record = &mm_dependency_table->entries[i]; mm_table->entries[i].vddcInd = mm_dependency_record->ucVddcInd; mm_table->entries[i].samclock = @@ -568,19 +933,27 @@ static int get_socclk_voltage_dependency_table( const ATOM_Vega10_SOCCLK_Dependency_Table *clk_dep_table) { uint32_t i; + uint32_t num_entries; phm_ppt_v1_clock_voltage_dependency_table *clk_table; PP_ASSERT_WITH_CODE(clk_dep_table->ucNumEntries, "Invalid PowerPlay Table!", return -1); - clk_table = kzalloc_flex(*clk_table, entries, - clk_dep_table->ucNumEntries); + num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries, + pp_entries_max(hwmgr, clk_dep_table, + sizeof(*clk_dep_table), + sizeof(ATOM_Vega10_CLK_Dependency_Record))); + if (num_entries < clk_dep_table->ucNumEntries) + pr_warn("amdgpu: Vega10 SOCCLK dependency table: clamping ucNumEntries %u -> %u\n", + clk_dep_table->ucNumEntries, num_entries); + + clk_table = kzalloc_flex(*clk_table, entries, num_entries); if (!clk_table) return -ENOMEM; - clk_table->count = (uint32_t)clk_dep_table->ucNumEntries; + clk_table->count = num_entries; - for (i = 0; i < clk_dep_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { clk_table->entries[i].vddInd = clk_dep_table->entries[i].ucVddInd; clk_table->entries[i].clk = @@ -598,19 +971,27 @@ static int get_mclk_voltage_dependency_table( const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table) { uint32_t i; + uint32_t num_entries; phm_ppt_v1_clock_voltage_dependency_table *mclk_table; PP_ASSERT_WITH_CODE(mclk_dep_table->ucNumEntries, "Invalid PowerPlay Table!", return -1); - mclk_table = kzalloc_flex(*mclk_table, entries, - mclk_dep_table->ucNumEntries); + num_entries = min_t(uint32_t, mclk_dep_table->ucNumEntries, + pp_entries_max(hwmgr, mclk_dep_table, + sizeof(*mclk_dep_table), + sizeof(ATOM_Vega10_MCLK_Dependency_Record))); + if (num_entries < mclk_dep_table->ucNumEntries) + pr_warn("amdgpu: Vega10 MCLK dependency table: clamping ucNumEntries %u -> %u\n", + mclk_dep_table->ucNumEntries, num_entries); + + mclk_table = kzalloc_flex(*mclk_table, entries, num_entries); if (!mclk_table) return -ENOMEM; - mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries; + mclk_table->count = num_entries; - for (i = 0; i < mclk_dep_table->ucNumEntries; i++) { + for (i = 0; i < num_entries; i++) { mclk_table->entries[i].vddInd = mclk_dep_table->entries[i].ucVddInd; mclk_table->entries[i].vddciInd = @@ -633,6 +1014,7 @@ static int get_gfxclk_voltage_dependency_table( const ATOM_Vega10_GFXCLK_Dependency_Table *clk_dep_table) { uint32_t i; + uint32_t num_entries; struct phm_ppt_v1_clock_voltage_dependency_table *clk_table; ATOM_Vega10_GFXCLK_Dependency_Record_V2 *patom_record_v2; @@ -640,15 +1022,34 @@ static int get_gfxclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - clk_table = kzalloc_flex(*clk_table, entries, - clk_dep_table->ucNumEntries); + if (clk_dep_table->ucRevId == 0) { + num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries, + pp_entries_max(hwmgr, clk_dep_table, + sizeof(*clk_dep_table), + sizeof(ATOM_Vega10_GFXCLK_Dependency_Record))); + } else if (clk_dep_table->ucRevId == 1) { + num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries, + pp_entries_max(hwmgr, clk_dep_table, + sizeof(*clk_dep_table), + sizeof(ATOM_Vega10_GFXCLK_Dependency_Record_V2))); + } else { + PP_ASSERT_WITH_CODE(false, + "Unsupported GFXClockDependencyTable Revision!", + return -EINVAL); + } + + if (num_entries < clk_dep_table->ucNumEntries) + pr_warn("amdgpu: Vega10 GFXCLK dependency table: clamping ucNumEntries %u -> %u\n", + clk_dep_table->ucNumEntries, num_entries); + + clk_table = kzalloc_flex(*clk_table, entries, num_entries); if (!clk_table) return -ENOMEM; - clk_table->count = clk_dep_table->ucNumEntries; + clk_table->count = num_entries; if (clk_dep_table->ucRevId == 0) { - for (i = 0; i < clk_table->count; i++) { + for (i = 0; i < num_entries; i++) { clk_table->entries[i].vddInd = clk_dep_table->entries[i].ucVddInd; clk_table->entries[i].clk = @@ -661,9 +1062,9 @@ static int get_gfxclk_voltage_dependency_table( clk_table->entries[i].sclk_offset = le16_to_cpu(clk_dep_table->entries[i].usAVFSOffset); } - } else if (clk_dep_table->ucRevId == 1) { + } else { patom_record_v2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)clk_dep_table->entries; - for (i = 0; i < clk_table->count; i++) { + for (i = 0; i < num_entries; i++) { clk_table->entries[i].vddInd = patom_record_v2->ucVddInd; clk_table->entries[i].clk = @@ -677,11 +1078,6 @@ static int get_gfxclk_voltage_dependency_table( le16_to_cpu(patom_record_v2->usAVFSOffset); patom_record_v2++; } - } else { - kfree(clk_table); - PP_ASSERT_WITH_CODE(false, - "Unsupported GFXClockDependencyTable Revision!", - return -EINVAL); } *pp_vega10_clk_dep_table = clk_table; @@ -696,20 +1092,28 @@ static int get_pix_clk_voltage_dependency_table( const ATOM_Vega10_PIXCLK_Dependency_Table *clk_dep_table) { uint32_t i; + uint32_t num_entries; struct phm_ppt_v1_clock_voltage_dependency_table *clk_table; PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); - clk_table = kzalloc_flex(*clk_table, entries, - clk_dep_table->ucNumEntries); + num_entries = min_t(uint32_t, clk_dep_table->ucNumEntries, + pp_entries_max(hwmgr, clk_dep_table, + sizeof(*clk_dep_table), + sizeof(ATOM_Vega10_CLK_Dependency_Record))); + if (num_entries < clk_dep_table->ucNumEntries) + pr_warn("amdgpu: Vega10 PIXCLK dependency table: clamping ucNumEntries %u -> %u\n", + clk_dep_table->ucNumEntries, num_entries); + + clk_table = kzalloc_flex(*clk_table, entries, num_entries); if (!clk_table) return -ENOMEM; - clk_table->count = clk_dep_table->ucNumEntries; + clk_table->count = num_entries; - for (i = 0; i < clk_table->count; i++) { + for (i = 0; i < num_entries; i++) { clk_table->entries[i].vddInd = clk_dep_table->entries[i].ucVddInd; clk_table->entries[i].clk = @@ -728,6 +1132,7 @@ static int get_dcefclk_voltage_dependency_table( const ATOM_Vega10_DCEFCLK_Dependency_Table *clk_dep_table) { uint32_t i; + uint32_t safe_entries; uint8_t num_entries; struct phm_ppt_v1_clock_voltage_dependency_table *clk_table; @@ -738,6 +1143,14 @@ static int get_dcefclk_voltage_dependency_table( PP_ASSERT_WITH_CODE((clk_dep_table->ucNumEntries != 0), "Invalid PowerPlay Table!", return -1); + safe_entries = min_t(uint32_t, clk_dep_table->ucNumEntries, + pp_entries_max(hwmgr, clk_dep_table, + sizeof(*clk_dep_table), + sizeof(ATOM_Vega10_CLK_Dependency_Record))); + if (safe_entries < clk_dep_table->ucNumEntries) + pr_warn("amdgpu: Vega10 DCEFCLK dependency table: clamping ucNumEntries %u -> %u\n", + clk_dep_table->ucNumEntries, safe_entries); + /* * workaround needed to add another DPM level for pioneer cards * as VBIOS is locked down. @@ -747,12 +1160,12 @@ static int get_dcefclk_voltage_dependency_table( dev_id = adev->pdev->device; rev_id = adev->pdev->revision; - if (dev_id == 0x6863 && rev_id == 0 && - clk_dep_table->entries[clk_dep_table->ucNumEntries - 1].ulClk < 90000) - num_entries = clk_dep_table->ucNumEntries + 1 > NUM_DSPCLK_LEVELS ? - NUM_DSPCLK_LEVELS : clk_dep_table->ucNumEntries + 1; + if (dev_id == 0x6863 && rev_id == 0 && safe_entries > 0 && + clk_dep_table->entries[safe_entries - 1].ulClk < 90000) + num_entries = safe_entries + 1 > NUM_DSPCLK_LEVELS ? + NUM_DSPCLK_LEVELS : safe_entries + 1; else - num_entries = clk_dep_table->ucNumEntries; + num_entries = safe_entries; clk_table = kzalloc_flex(*clk_table, entries, num_entries); @@ -761,7 +1174,7 @@ static int get_dcefclk_voltage_dependency_table( clk_table->count = (uint32_t)num_entries; - for (i = 0; i < clk_dep_table->ucNumEntries; i++) { + for (i = 0; i < safe_entries; i++) { clk_table->entries[i].vddInd = clk_dep_table->entries[i].ucVddInd; clk_table->entries[i].clk = @@ -873,51 +1286,13 @@ static int init_powerplay_extended_tables( int result = 0; struct phm_ppt_v2_information *pp_table_info = (struct phm_ppt_v2_information *)(hwmgr->pptable); - - const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table = - (const ATOM_Vega10_MM_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usMMDependencyTableOffset)); - const Vega10_PPTable_Generic_SubTable_Header *power_tune_table = - (const Vega10_PPTable_Generic_SubTable_Header *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usPowerTuneTableOffset)); - const ATOM_Vega10_SOCCLK_Dependency_Table *socclk_dep_table = - (const ATOM_Vega10_SOCCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset)); - const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table = - (const ATOM_Vega10_GFXCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usGfxclkDependencyTableOffset)); - const ATOM_Vega10_DCEFCLK_Dependency_Table *dcefclk_dep_table = - (const ATOM_Vega10_DCEFCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usDcefclkDependencyTableOffset)); - const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table = - (const ATOM_Vega10_MCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usMclkDependencyTableOffset)); - const ATOM_Vega10_Hard_Limit_Table *hard_limits = - (const ATOM_Vega10_Hard_Limit_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usHardLimitTableOffset)); - const Vega10_PPTable_Generic_SubTable_Header *pcie_table = - (const Vega10_PPTable_Generic_SubTable_Header *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usPCIETableOffset)); - const ATOM_Vega10_PIXCLK_Dependency_Table *pixclk_dep_table = - (const ATOM_Vega10_PIXCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usPixclkDependencyTableOffset)); - const ATOM_Vega10_PHYCLK_Dependency_Table *phyclk_dep_table = - (const ATOM_Vega10_PHYCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usPhyClkDependencyTableOffset)); - const ATOM_Vega10_DISPCLK_Dependency_Table *dispclk_dep_table = - (const ATOM_Vega10_DISPCLK_Dependency_Table *) - (((unsigned long) powerplay_table) + - le16_to_cpu(powerplay_table->usDispClkDependencyTableOffset)); + const ATOM_Vega10_MM_Dependency_Table *mm_dependency_table; + const Vega10_PPTable_Generic_SubTable_Header *power_tune_table; + const ATOM_Vega10_GFXCLK_Dependency_Table *gfxclk_dep_table; + const ATOM_Vega10_MCLK_Dependency_Table *mclk_dep_table; + const ATOM_Vega10_Hard_Limit_Table *hard_limits; + const Vega10_PPTable_Generic_SubTable_Header *pcie_table; + const ATOM_Vega10_SOCCLK_Dependency_Table *clk_dep_table; pp_table_info->vdd_dep_on_socclk = NULL; pp_table_info->vdd_dep_on_sclk = NULL; @@ -929,63 +1304,114 @@ static int init_powerplay_extended_tables( pp_table_info->vdd_dep_on_phyclk = NULL; pp_table_info->vdd_dep_on_dispclk = NULL; - if (powerplay_table->usMMDependencyTableOffset) - result = get_mm_clock_voltage_table(hwmgr, + if (powerplay_table->usMMDependencyTableOffset) { + result = get_vega10_mm_dependency_table(hwmgr, powerplay_table, + &mm_dependency_table); + if (!result) + result = get_mm_clock_voltage_table(hwmgr, &pp_table_info->mm_dep_table, mm_dependency_table); + } - if (!result && powerplay_table->usPowerTuneTableOffset) - result = get_tdp_table(hwmgr, + if (!result && powerplay_table->usPowerTuneTableOffset) { + result = get_vega10_power_tune_table(hwmgr, powerplay_table, + &power_tune_table); + if (!result) + result = get_tdp_table(hwmgr, &pp_table_info->tdp_table, power_tune_table); + } - if (!result && powerplay_table->usSocclkDependencyTableOffset) - result = get_socclk_voltage_dependency_table(hwmgr, + if (!result && powerplay_table->usSocclkDependencyTableOffset) { + result = get_vega10_clk_dependency_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usSocclkDependencyTableOffset), + &clk_dep_table); + if (!result) + result = get_socclk_voltage_dependency_table(hwmgr, &pp_table_info->vdd_dep_on_socclk, - socclk_dep_table); + (const ATOM_Vega10_SOCCLK_Dependency_Table *) + clk_dep_table); + } - if (!result && powerplay_table->usGfxclkDependencyTableOffset) - result = get_gfxclk_voltage_dependency_table(hwmgr, - &pp_table_info->vdd_dep_on_sclk, - gfxclk_dep_table); + if (!result && powerplay_table->usGfxclkDependencyTableOffset) { + result = get_vega10_gfxclk_dependency_table(hwmgr, + powerplay_table, &gfxclk_dep_table); + if (!result) + result = get_gfxclk_voltage_dependency_table(hwmgr, + &pp_table_info->vdd_dep_on_sclk, + gfxclk_dep_table); + } - if (!result && powerplay_table->usPixclkDependencyTableOffset) - result = get_pix_clk_voltage_dependency_table(hwmgr, + if (!result && powerplay_table->usPixclkDependencyTableOffset) { + result = get_vega10_clk_dependency_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usPixclkDependencyTableOffset), + &clk_dep_table); + if (!result) + result = get_pix_clk_voltage_dependency_table(hwmgr, &pp_table_info->vdd_dep_on_pixclk, (const ATOM_Vega10_PIXCLK_Dependency_Table *) - pixclk_dep_table); + clk_dep_table); + } - if (!result && powerplay_table->usPhyClkDependencyTableOffset) - result = get_pix_clk_voltage_dependency_table(hwmgr, + if (!result && powerplay_table->usPhyClkDependencyTableOffset) { + result = get_vega10_clk_dependency_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usPhyClkDependencyTableOffset), + &clk_dep_table); + if (!result) + result = get_pix_clk_voltage_dependency_table(hwmgr, &pp_table_info->vdd_dep_on_phyclk, (const ATOM_Vega10_PIXCLK_Dependency_Table *) - phyclk_dep_table); + clk_dep_table); + } - if (!result && powerplay_table->usDispClkDependencyTableOffset) - result = get_pix_clk_voltage_dependency_table(hwmgr, + if (!result && powerplay_table->usDispClkDependencyTableOffset) { + result = get_vega10_clk_dependency_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usDispClkDependencyTableOffset), + &clk_dep_table); + if (!result) + result = get_pix_clk_voltage_dependency_table(hwmgr, &pp_table_info->vdd_dep_on_dispclk, (const ATOM_Vega10_PIXCLK_Dependency_Table *) - dispclk_dep_table); + clk_dep_table); + } - if (!result && powerplay_table->usDcefclkDependencyTableOffset) - result = get_dcefclk_voltage_dependency_table(hwmgr, + if (!result && powerplay_table->usDcefclkDependencyTableOffset) { + result = get_vega10_clk_dependency_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usDcefclkDependencyTableOffset), + &clk_dep_table); + if (!result) + result = get_dcefclk_voltage_dependency_table(hwmgr, &pp_table_info->vdd_dep_on_dcefclk, - dcefclk_dep_table); + (const ATOM_Vega10_DCEFCLK_Dependency_Table *) + clk_dep_table); + } - if (!result && powerplay_table->usMclkDependencyTableOffset) - result = get_mclk_voltage_dependency_table(hwmgr, + if (!result && powerplay_table->usMclkDependencyTableOffset) { + result = get_vega10_mclk_dependency_table(hwmgr, powerplay_table, + &mclk_dep_table); + if (!result) + result = get_mclk_voltage_dependency_table(hwmgr, &pp_table_info->vdd_dep_on_mclk, mclk_dep_table); + } - if (!result && powerplay_table->usPCIETableOffset) - result = get_pcie_table(hwmgr, + if (!result && powerplay_table->usPCIETableOffset) { + result = get_vega10_pcie_table(hwmgr, powerplay_table, + &pcie_table); + if (!result) + result = get_pcie_table(hwmgr, &pp_table_info->pcie_table, pcie_table); + } - if (!result && powerplay_table->usHardLimitTableOffset) - result = get_hard_limits(hwmgr, + if (!result && powerplay_table->usHardLimitTableOffset) { + result = get_vega10_hard_limit_table(hwmgr, powerplay_table, + &hard_limits); + if (!result) + result = get_hard_limits(hwmgr, &pp_table_info->max_clock_voltage_on_dc, hard_limits); + } hwmgr->dyn_state.max_clock_voltage_on_dc.sclk = pp_table_info->max_clock_voltage_on_dc.sclk; @@ -1034,18 +1460,28 @@ static int get_vddc_lookup_table( uint32_t max_levels) { uint32_t i; + uint32_t num_entries; phm_ppt_v1_voltage_lookup_table *table; PP_ASSERT_WITH_CODE((vddc_lookup_pp_tables->ucNumEntries != 0), "Invalid SOC_VDDD Lookup Table!", return 1); - table = kzalloc_flex(*table, entries, max_levels); + num_entries = min_t(uint32_t, vddc_lookup_pp_tables->ucNumEntries, + min_t(uint32_t, max_levels, + pp_entries_max(hwmgr, vddc_lookup_pp_tables, + sizeof(*vddc_lookup_pp_tables), + sizeof(ATOM_Vega10_Voltage_Lookup_Record)))); + if (num_entries < vddc_lookup_pp_tables->ucNumEntries) + pr_warn("amdgpu: Vega10 VddcLookup table: clamping ucNumEntries %u -> %u\n", + vddc_lookup_pp_tables->ucNumEntries, num_entries); + + table = kzalloc_flex(*table, entries, num_entries); if (!table) return -ENOMEM; - table->count = vddc_lookup_pp_tables->ucNumEntries; + table->count = num_entries; - for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) + for (i = 0; i < num_entries; i++) table->entries[i].us_vdd = le16_to_cpu(vddc_lookup_pp_tables->entries[i].usVdd); @@ -1113,30 +1549,39 @@ static int init_dpm_2_parameters( } if (powerplay_table->usVddcLookupTableOffset) { - const ATOM_Vega10_Voltage_Lookup_Table *vddc_table = - (ATOM_Vega10_Voltage_Lookup_Table *) - (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usVddcLookupTableOffset)); - result = get_vddc_lookup_table(hwmgr, - &pp_table_info->vddc_lookup_table, vddc_table, 8); + const ATOM_Vega10_Voltage_Lookup_Table *vddc_table; + + result = get_vega10_voltage_lookup_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usVddcLookupTableOffset), + 8, &vddc_table); + if (!result) + result = get_vddc_lookup_table(hwmgr, + &pp_table_info->vddc_lookup_table, + vddc_table, 8); } - if (powerplay_table->usVddmemLookupTableOffset) { - const ATOM_Vega10_Voltage_Lookup_Table *vdd_mem_table = - (ATOM_Vega10_Voltage_Lookup_Table *) - (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usVddmemLookupTableOffset)); - result = get_vddc_lookup_table(hwmgr, - &pp_table_info->vddmem_lookup_table, vdd_mem_table, 4); + if (!result && powerplay_table->usVddmemLookupTableOffset) { + const ATOM_Vega10_Voltage_Lookup_Table *vdd_mem_table; + + result = get_vega10_voltage_lookup_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usVddmemLookupTableOffset), + 4, &vdd_mem_table); + if (!result) + result = get_vddc_lookup_table(hwmgr, + &pp_table_info->vddmem_lookup_table, + vdd_mem_table, 4); } - if (powerplay_table->usVddciLookupTableOffset) { - const ATOM_Vega10_Voltage_Lookup_Table *vddci_table = - (ATOM_Vega10_Voltage_Lookup_Table *) - (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table->usVddciLookupTableOffset)); - result = get_vddc_lookup_table(hwmgr, - &pp_table_info->vddci_lookup_table, vddci_table, 4); + if (!result && powerplay_table->usVddciLookupTableOffset) { + const ATOM_Vega10_Voltage_Lookup_Table *vddci_table; + + result = get_vega10_voltage_lookup_table(hwmgr, powerplay_table, + le16_to_cpu(powerplay_table->usVddciLookupTableOffset), + 4, &vddci_table); + if (!result) + result = get_vddc_lookup_table(hwmgr, + &pp_table_info->vddci_lookup_table, + vddci_table, 4); } return result; @@ -1247,15 +1692,14 @@ int vega10_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr) { const ATOM_Vega10_State_Array *state_arrays; const ATOM_Vega10_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); + int result; PP_ASSERT_WITH_CODE((pp_table != NULL), "Missing PowerPlay Table!", return -1); - PP_ASSERT_WITH_CODE((pp_table->sHeader.format_revision >= - ATOM_Vega10_TABLE_REVISION_VEGA10), - "Incorrect PowerPlay table revision!", return -1); - state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)pp_table) + - le16_to_cpu(pp_table->usStateArrayOffset)); + result = get_vega10_state_array(hwmgr, pp_table, &state_arrays); + PP_ASSERT_WITH_CODE((result == 0), + "Invalid PowerPlay Table State Array.", return result); return (uint32_t)(state_arrays->ucNumEntries); } @@ -1306,17 +1750,11 @@ int vega10_get_powerplay_table_entry(struct pp_hwmgr *hwmgr, if (pp_table->sHeader.format_revision >= ATOM_Vega10_TABLE_REVISION_VEGA10) { - state_arrays = (ATOM_Vega10_State_Array *) - (((unsigned long)pp_table) + - le16_to_cpu(pp_table->usStateArrayOffset)); - - PP_ASSERT_WITH_CODE(pp_table->usStateArrayOffset > 0, - "Invalid PowerPlay Table State Array Offset.", - return -1); - PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0, + result = get_vega10_state_array(hwmgr, pp_table, &state_arrays); + PP_ASSERT_WITH_CODE((result == 0), "Invalid PowerPlay Table State Array.", - return -1); - PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), + return result); + PP_ASSERT_WITH_CODE((entry_index < state_arrays->ucNumEntries), "Invalid PowerPlay Table State Array Entry.", return -1); @@ -1358,4 +1796,3 @@ int vega10_baco_set_cap(struct pp_hwmgr *hwmgr) PHM_PlatformCaps_BACO); return result; } - diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c index 55e13f376039..dcb9c749eba3 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c @@ -64,6 +64,13 @@ static int check_powerplay_tables( struct pp_hwmgr *hwmgr, const ATOM_Vega12_POWERPLAYTABLE *powerplay_table) { + size_t smc_pptable_size = + offsetofend(ATOM_Vega12_POWERPLAYTABLE, smcPPTable); + size_t table_size = hwmgr->soft_pp_table_size; + + PP_ASSERT_WITH_CODE((table_size >= smc_pptable_size), + "Invalid PowerPlay Table!", return -1); + PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >= ATOM_VEGA12_TABLE_REVISION_VEGA12), "Unsupported PPTable format!", return -1); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c index 36cb7aa80d07..a0c884c2341d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c @@ -66,6 +66,13 @@ static int check_powerplay_tables( struct pp_hwmgr *hwmgr, const ATOM_Vega20_POWERPLAYTABLE *powerplay_table) { + size_t smc_pptable_size = + offsetofend(ATOM_Vega20_POWERPLAYTABLE, smcPPTable); + size_t table_size = hwmgr->soft_pp_table_size; + + PP_ASSERT_WITH_CODE((table_size >= smc_pptable_size), + "Invalid PowerPlay Table!", return -1); + PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >= ATOM_VEGA20_TABLE_REVISION_VEGA20), "Unsupported PPTable format!", return -1); diff --git a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h index ca71efaa1656..7ebc1344023f 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/pm/powerplay/inc/hwmgr.h @@ -829,4 +829,21 @@ int smu8_init_function_pointers(struct pp_hwmgr *hwmgr); int vega12_hwmgr_init(struct pp_hwmgr *hwmgr); int vega20_hwmgr_init(struct pp_hwmgr *hwmgr); +static inline uint32_t pp_entries_max(const struct pp_hwmgr *hwmgr, + const void *sub_table, + size_t hdr_size, size_t rec_size) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)hwmgr->adev; + const char *bios_end = (const char *)adev->bios + adev->bios_size; + const char *pp_end = (const char *)hwmgr->soft_pp_table + + hwmgr->soft_pp_table_size; + const char *entries = (const char *)sub_table + hdr_size; + + if (pp_end > bios_end) + return 0; + if (!rec_size || entries >= pp_end) + return 0; + return (uint32_t)((pp_end - entries) / rec_size); +} + #endif /* _HWMGR_H_ */ diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 208a2fba6d40..541cf0a985eb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -591,17 +591,13 @@ static int smu_get_power_num_states(void *handle, return 0; } -bool is_support_sw_smu(struct amdgpu_device *adev) +void amdgpu_smu_early_init(struct amdgpu_device *adev) { /* vega20 is 11.0.2, but it's supported via the powerplay code */ - if (adev->asic_type == CHIP_VEGA20) - return false; - - if ((amdgpu_ip_version(adev, MP1_HWIP, 0) >= IP_VERSION(11, 0, 0)) && - amdgpu_device_ip_is_valid(adev, AMD_IP_BLOCK_TYPE_SMC)) - return true; - - return false; + adev->is_sw_smu = adev->asic_type != CHIP_VEGA20 && + (amdgpu_ip_version(adev, MP1_HWIP, 0) >= + IP_VERSION(11, 0, 0) && + amdgpu_device_ip_is_valid(adev, AMD_IP_BLOCK_TYPE_SMC)); } bool is_support_cclk_dpm(struct amdgpu_device *adev) @@ -667,25 +663,28 @@ static int smu_sys_set_pp_table(void *handle, { struct smu_context *smu = handle; struct smu_table_context *smu_table = &smu->smu_table; - ATOM_COMMON_TABLE_HEADER *header = (ATOM_COMMON_TABLE_HEADER *)buf; + ATOM_COMMON_TABLE_HEADER *header; + void *hardcode_pptable; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; + if (!buf || size < sizeof(*header)) + return -EINVAL; + + header = (ATOM_COMMON_TABLE_HEADER *)buf; if (header->usStructureSize != size) { dev_err(smu->adev->dev, "pp table size not matched !\n"); return -EIO; } - if (!smu_table->hardcode_pptable || smu_table->power_play_table_size < size) { - kfree(smu_table->hardcode_pptable); - smu_table->hardcode_pptable = kzalloc(size, GFP_KERNEL); - if (!smu_table->hardcode_pptable) - return -ENOMEM; - } + hardcode_pptable = kmemdup(buf, size, GFP_KERNEL); + if (!hardcode_pptable) + return -ENOMEM; - memcpy(smu_table->hardcode_pptable, buf, size); + kfree(smu_table->hardcode_pptable); + smu_table->hardcode_pptable = hardcode_pptable; smu_table->power_play_table = smu_table->hardcode_pptable; smu_table->power_play_table_size = size; @@ -2772,7 +2771,6 @@ const struct amd_ip_funcs smu_ip_funcs = { .suspend = smu_suspend, .resume = smu_resume, .is_idle = NULL, - .check_soft_reset = NULL, .wait_for_idle = NULL, .soft_reset = NULL, .set_clockgating_state = smu_set_clockgating_state, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h index d76e0b005308..378781c05bea 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/amdgpu_smu.h @@ -849,8 +849,6 @@ struct pptable_funcs { */ int (*set_default_dpm_table)(struct smu_context *smu); - int (*set_power_state)(struct smu_context *smu); - /** * @populate_umd_state_clk: Populate the UMD power state table with * defaults. @@ -903,16 +901,6 @@ struct pptable_funcs { struct pp_clock_levels_with_latency *clocks); - /** - * @get_clock_by_type_with_voltage: Get the speed and voltage of a clock - * domain. - */ - int (*get_clock_by_type_with_voltage)(struct smu_context *smu, - enum amd_pp_clock_type type, - struct - pp_clock_levels_with_voltage - *clocks); - /** * @get_power_profile_mode: Print all power profile modes to * buffer. Star current mode. @@ -1354,11 +1342,6 @@ struct pptable_funcs { */ int (*register_irq_handler)(struct smu_context *smu); - /** - * @set_azalia_d3_pme: Wake the audio decode engine from d3 sleep. - */ - int (*set_azalia_d3_pme)(struct smu_context *smu); - /** * @get_max_sustainable_clocks_by_dc: Get a copy of the max sustainable * clock speeds table. @@ -1375,18 +1358,6 @@ struct pptable_funcs { */ int (*get_bamaco_support)(struct smu_context *smu); - /** - * @baco_get_state: Get the current BACO state. - * - * Return: Current BACO state. - */ - enum smu_baco_state (*baco_get_state)(struct smu_context *smu); - - /** - * @baco_set_state: Enter/exit BACO. - */ - int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state); - /** * @baco_enter: Enter BACO. */ @@ -1952,7 +1923,13 @@ int smu_link_reset(struct smu_context *smu); extern const struct amd_ip_funcs smu_ip_funcs; -bool is_support_sw_smu(struct amdgpu_device *adev); +void amdgpu_smu_early_init(struct amdgpu_device *adev); + +static inline bool is_support_sw_smu(struct amdgpu_device *adev) +{ + return adev->is_sw_smu; +} + bool is_support_cclk_dpm(struct amdgpu_device *adev); int smu_write_watermarks_table(struct smu_context *smu); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h index dd94e8a9e218..c0accee9a9c8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v11_0.h @@ -199,8 +199,6 @@ int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable); int smu_v11_0_register_irq_handler(struct smu_context *smu); -int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu); - int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks); diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h index 89bbda0670ef..7f21f867d73c 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v13_0.h @@ -180,8 +180,6 @@ int smu_v13_0_gfx_off_control(struct smu_context *smu, bool enable); int smu_v13_0_register_irq_handler(struct smu_context *smu); -int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu); - int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks); @@ -255,10 +253,6 @@ void smu_v13_0_init_msg_ctl(struct smu_context *smu, int smu_v13_0_mode1_reset(struct smu_context *smu); -int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu, - void **table, - uint32_t *size, - uint32_t pptable_id); int smu_v13_0_update_pcie_parameters(struct smu_context *smu, uint8_t pcie_gen_cap, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h index 4eb40ff8aff2..dc8e13a7c879 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v14_0.h @@ -203,10 +203,6 @@ int smu_v14_0_set_gfx_power_up_by_imu(struct smu_context *smu); int smu_v14_0_set_default_dpm_tables(struct smu_context *smu); -int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu, - void **table, - uint32_t *size, - uint32_t pptable_id); int smu_v14_0_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, diff --git a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h index e6fd8be2cc4a..13723d45a7de 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h +++ b/drivers/gpu/drm/amd/pm/swsmu/inc/smu_v15_0.h @@ -211,10 +211,6 @@ int smu_v15_0_deep_sleep_control(struct smu_context *smu, int smu_v15_0_set_gfx_power_up_by_imu(struct smu_context *smu); -int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu, - void **table, - uint32_t *size, - uint32_t pptable_id); int smu_v15_0_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c index 54d3dba7d354..db5db2c9c8e8 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c @@ -1466,9 +1466,10 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu, return -ENOMEM; } if (custom_params && custom_params_max_idx) { - if (custom_params_max_idx != ARCTURUS_CUSTOM_PARAMS_COUNT) - return -EINVAL; - if (custom_params[0] >= ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT) + if (!smu_cmn_custom_params_count_valid(custom_params_max_idx, + ARCTURUS_CUSTOM_PARAMS_COUNT) || + !smu_cmn_custom_params_clock_valid(custom_params[0], + ARCTURUS_CUSTOM_PARAMS_CLOCK_COUNT)) return -EINVAL; idx = custom_params[0] * ARCTURUS_CUSTOM_PARAMS_COUNT; smu->custom_profile_params[idx] = 1; @@ -1932,7 +1933,6 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, .gfx_off_control = smu_v11_0_gfx_off_control, .register_irq_handler = smu_v11_0_register_irq_handler, - .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, .get_bamaco_support = smu_v11_0_get_bamaco_support, .baco_enter = smu_v11_0_baco_enter, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c index cd0457e13f54..8feea44f3ca0 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c @@ -1843,9 +1843,10 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, return -ENOMEM; } if (custom_params && custom_params_max_idx) { - if (custom_params_max_idx != NAVI10_CUSTOM_PARAMS_COUNT) - return -EINVAL; - if (custom_params[0] >= NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT) + if (!smu_cmn_custom_params_count_valid(custom_params_max_idx, + NAVI10_CUSTOM_PARAMS_COUNT) || + !smu_cmn_custom_params_clock_valid(custom_params[0], + NAVI10_CUSTOM_PARAMS_CLOCKS_COUNT)) return -EINVAL; idx = custom_params[0] * NAVI10_CUSTOM_PARAMS_COUNT; smu->custom_profile_params[idx] = 1; @@ -3337,7 +3338,6 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, .gfx_off_control = smu_v11_0_gfx_off_control, .register_irq_handler = smu_v11_0_register_irq_handler, - .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, .get_bamaco_support = smu_v11_0_get_bamaco_support, .baco_enter = navi10_baco_enter, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c index f799e489b481..c0de73b85353 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c @@ -1755,9 +1755,10 @@ static int sienna_cichlid_set_power_profile_mode(struct smu_context *smu, return -ENOMEM; } if (custom_params && custom_params_max_idx) { - if (custom_params_max_idx != SIENNA_CICHLID_CUSTOM_PARAMS_COUNT) - return -EINVAL; - if (custom_params[0] >= SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT) + if (!smu_cmn_custom_params_count_valid(custom_params_max_idx, + SIENNA_CICHLID_CUSTOM_PARAMS_COUNT) || + !smu_cmn_custom_params_clock_valid(custom_params[0], + SIENNA_CICHLID_CUSTOM_PARAMS_CLOCK_COUNT)) return -EINVAL; idx = custom_params[0] * SIENNA_CICHLID_CUSTOM_PARAMS_COUNT; smu->custom_profile_params[idx] = 1; @@ -3144,7 +3145,6 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = { .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, .gfx_off_control = smu_v11_0_gfx_off_control, .register_irq_handler = smu_v11_0_register_irq_handler, - .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, .get_bamaco_support = smu_v11_0_get_bamaco_support, .baco_enter = sienna_cichlid_baco_enter, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index d68ceee16d8f..a889d846e9c5 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -192,81 +192,22 @@ int smu_v11_0_check_fw_status(struct smu_context *smu) return -EIO; } -static int smu_v11_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t ppt_offset_bytes; - const struct smc_firmware_header_v2_0 *v2; - - v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data; - - ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes); - *size = le32_to_cpu(v2->ppt_size_bytes); - *table = (uint8_t *)v2 + ppt_offset_bytes; - - return 0; -} - -static int smu_v11_0_set_pptable_v2_1(struct smu_context *smu, void **table, - uint32_t *size, uint32_t pptable_id) -{ - struct amdgpu_device *adev = smu->adev; - const struct smc_firmware_header_v2_1 *v2_1; - struct smc_soft_pptable_entry *entries; - uint32_t pptable_count = 0; - int i = 0; - - v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data; - entries = (struct smc_soft_pptable_entry *) - ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset)); - pptable_count = le32_to_cpu(v2_1->pptable_count); - for (i = 0; i < pptable_count; i++) { - if (le32_to_cpu(entries[i].id) == pptable_id) { - *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes)); - *size = le32_to_cpu(entries[i].ppt_size_bytes); - break; - } - } - - if (i == pptable_count) - return -EINVAL; - - return 0; -} - int smu_v11_0_setup_pptable(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - const struct smc_firmware_header_v1_0 *hdr; - int ret, index; - uint32_t size = 0; uint16_t atom_table_size; uint8_t frev, crev; + uint32_t size = 0; + int ret, index; void *table; - uint16_t version_major, version_minor; - if (!amdgpu_sriov_vf(adev)) { - hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; - version_major = le16_to_cpu(hdr->header.header_version_major); - version_minor = le16_to_cpu(hdr->header.header_version_minor); - if (version_major == 2 && smu->smu_table.boot_values.pp_table_id > 0) { - dev_info(adev->dev, "use driver provided pptable %d\n", smu->smu_table.boot_values.pp_table_id); - switch (version_minor) { - case 0: - ret = smu_v11_0_set_pptable_v2_0(smu, &table, &size); - break; - case 1: - ret = smu_v11_0_set_pptable_v2_1(smu, &table, &size, - smu->smu_table.boot_values.pp_table_id); - break; - default: - ret = -EINVAL; - break; - } - if (ret) - return ret; - goto out; - } + if (!amdgpu_sriov_vf(adev) && + smu->smu_table.boot_values.pp_table_id > 0) { + ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, + smu->smu_table.boot_values.pp_table_id); + if (ret) + return ret; + goto out; } dev_info(adev->dev, "use vbios provided pptable\n"); @@ -1476,11 +1417,6 @@ int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, return 0; } -int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu) -{ - return smu_cmn_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME, NULL); -} - int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu, enum smu_baco_seq baco_seq) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c index 75335da224c7..2b011610e3c7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_ppt.c @@ -1444,7 +1444,6 @@ static int renoir_get_enabled_mask(struct smu_context *smu, } static const struct pptable_funcs renoir_ppt_funcs = { - .set_power_state = NULL, .emit_clk_levels = renoir_emit_clk_levels, .get_current_power_state = renoir_get_current_power_state, .dpm_set_vcn_enable = renoir_dpm_set_vcn_enable, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c index 9d8b1227388f..cd7bf36673cb 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c @@ -2004,7 +2004,6 @@ static const struct pptable_funcs aldebaran_ppt_funcs = { .disable_thermal_alert = smu_v13_0_disable_thermal_alert, .set_xgmi_pstate = smu_v13_0_set_xgmi_pstate, .register_irq_handler = smu_v13_0_register_irq_handler, - .set_azalia_d3_pme = smu_v13_0_set_azalia_d3_pme, .get_max_sustainable_clocks_by_dc = smu_v13_0_get_max_sustainable_clocks_by_dc, .get_bamaco_support = aldebaran_get_bamaco_support, .get_dpm_ultimate_freq = aldebaran_get_dpm_ultimate_freq, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c index be9a7a32de99..4f10bce36756 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c @@ -218,7 +218,7 @@ int smu_v13_0_init_pptable_microcode(struct smu_context *smu) if (!pptable_id) return 0; - ret = smu_v13_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id); if (ret) return ret; @@ -258,48 +258,6 @@ int smu_v13_0_check_fw_status(struct smu_context *smu) return -EIO; } -static int smu_v13_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t ppt_offset_bytes; - const struct smc_firmware_header_v2_0 *v2; - - v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data; - - ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes); - *size = le32_to_cpu(v2->ppt_size_bytes); - *table = (uint8_t *)v2 + ppt_offset_bytes; - - return 0; -} - -static int smu_v13_0_set_pptable_v2_1(struct smu_context *smu, void **table, - uint32_t *size, uint32_t pptable_id) -{ - struct amdgpu_device *adev = smu->adev; - const struct smc_firmware_header_v2_1 *v2_1; - struct smc_soft_pptable_entry *entries; - uint32_t pptable_count = 0; - int i = 0; - - v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data; - entries = (struct smc_soft_pptable_entry *) - ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset)); - pptable_count = le32_to_cpu(v2_1->pptable_count); - for (i = 0; i < pptable_count; i++) { - if (le32_to_cpu(entries[i].id) == pptable_id) { - *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes)); - *size = le32_to_cpu(entries[i].ppt_size_bytes); - break; - } - } - - if (i == pptable_count) - return -EINVAL; - - return 0; -} - static int smu_v13_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -322,45 +280,6 @@ static int smu_v13_0_get_pptable_from_vbios(struct smu_context *smu, void **tabl return 0; } -int smu_v13_0_get_pptable_from_firmware(struct smu_context *smu, - void **table, - uint32_t *size, - uint32_t pptable_id) -{ - const struct smc_firmware_header_v1_0 *hdr; - struct amdgpu_device *adev = smu->adev; - uint16_t version_major, version_minor; - int ret; - - hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; - if (!hdr) - return -EINVAL; - - dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id); - - version_major = le16_to_cpu(hdr->header.header_version_major); - version_minor = le16_to_cpu(hdr->header.header_version_minor); - if (version_major != 2) { - dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n", - version_major, version_minor); - return -EINVAL; - } - - switch (version_minor) { - case 0: - ret = smu_v13_0_set_pptable_v2_0(smu, table, size); - break; - case 1: - ret = smu_v13_0_set_pptable_v2_1(smu, table, size, pptable_id); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - int smu_v13_0_setup_pptable(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -380,7 +299,7 @@ int smu_v13_0_setup_pptable(struct smu_context *smu) if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1)) ret = smu_v13_0_get_pptable_from_vbios(smu, &table, &size); else - ret = smu_v13_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id); if (ret) return ret; @@ -1401,15 +1320,6 @@ int smu_v13_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, return 0; } -int smu_v13_0_set_azalia_d3_pme(struct smu_context *smu) -{ - int ret = 0; - - ret = smu_cmn_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME, NULL); - - return ret; -} - static int smu_v13_0_wait_for_reset_complete(struct smu_context *smu, uint64_t event_arg) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 7f8d4bb47d02..4ce1429cf57b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -2403,11 +2403,14 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, uint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; - uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); + uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); + uint32_t od_percent_upper = 0, od_percent_lower = 0; int ret; if (current_power_limit) { - ret = smu_v13_0_get_current_power_limit(smu, &power_limit); + ret = smu_v13_0_get_current_power_limit(smu, current_power_limit); if (ret) *current_power_limit = pp_limit; } @@ -2430,12 +2433,12 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu, od_percent_upper, od_percent_lower, pp_limit); if (max_power_limit) { - *max_power_limit = pp_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /= 100; } if (min_power_limit) { - *min_power_limit = pp_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /= 100; } @@ -2616,9 +2619,10 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu, return -ENOMEM; } if (custom_params && custom_params_max_idx) { - if (custom_params_max_idx != SMU_13_0_0_CUSTOM_PARAMS_COUNT) - return -EINVAL; - if (custom_params[0] >= SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT) + if (!smu_cmn_custom_params_count_valid(custom_params_max_idx, + SMU_13_0_0_CUSTOM_PARAMS_COUNT) || + !smu_cmn_custom_params_clock_valid(custom_params[0], + SMU_13_0_0_CUSTOM_PARAMS_CLOCK_COUNT)) return -EINVAL; idx = custom_params[0] * SMU_13_0_0_CUSTOM_PARAMS_COUNT; smu->custom_profile_params[idx] = 1; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c index fe929bd89058..dea27fcb2b20 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_12_ppt.c @@ -1042,7 +1042,7 @@ static int smu_v13_0_12_get_badpage_count(struct amdgpu_device *adev, uint32_t * /* eeprom is not ready */ if (ret != -EBUSY) return ret; - mdelay(10); + usleep_range(10000, 15000); now = (uint64_t)ktime_to_ms(ktime_get()); } while (now < end); @@ -1137,16 +1137,10 @@ static const struct ras_eeprom_smu_funcs smu_v13_0_12_eeprom_smu_funcs = { static void smu_v13_0_12_ras_smu_feature_flags(struct amdgpu_device *adev, uint64_t *flags) { - struct smu_context *smu = adev->powerplay.pp_handle; - if (!flags) return; *flags = 0ULL; - - if (smu_v13_0_6_cap_supported(smu, SMU_CAP(RAS_EEPROM))) - *flags |= RAS_SMU_FEATURE_BIT__RAS_EEPROM; - } const struct ras_smu_drv smu_v13_0_12_ras_smu_drv = { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index b12388134489..334c92a28994 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -44,8 +44,6 @@ #include "amdgpu_xgmi.h" #include #include "amdgpu_ras.h" -#include "amdgpu_mca.h" -#include "amdgpu_aca.h" #include "smu_cmn.h" #include "mp/mp_13_0_6_offset.h" #include "mp/mp_13_0_6_sh_mask.h" @@ -99,25 +97,6 @@ static const struct smu_feature_bits smu_v13_0_6_dpm_features = { #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK 0xE0 #define PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT 0x5 #define LINK_SPEED_MAX 4 -#define MCA_BANK_IPID(_ip, _hwid, _type) \ - [AMDGPU_MCA_IP_##_ip] = { .hwid = _hwid, .mcatype = _type, } - -struct mca_bank_ipid { - enum amdgpu_mca_ip ip; - uint16_t hwid; - uint16_t mcatype; -}; - -struct mca_ras_info { - enum amdgpu_ras_block blkid; - enum amdgpu_mca_ip ip; - int *err_code_array; - int err_code_count; - int (*get_err_count)(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count); - bool (*bank_is_valid)(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry); -}; #define P2S_TABLE_ID_A 0x50325341 #define P2S_TABLE_ID_X 0x50325358 @@ -1943,17 +1922,6 @@ static int smu_v13_0_6_notify_unload(struct smu_context *smu) return 0; } -static int smu_v13_0_6_mca_set_debug_mode(struct smu_context *smu, bool enable) -{ - /* NOTE: this ClearMcaOnRead message is only supported for smu version 85.72.0 or higher */ - if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(MCA_DEBUG_MODE))) - return 0; - - return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ClearMcaOnRead, - enable ? 0 : ClearMcaOnRead_UE_FLAG_MASK | ClearMcaOnRead_CE_POLL_MASK, - NULL); -} - static int smu_v13_0_6_system_features_control(struct smu_context *smu, bool enable) { @@ -3299,622 +3267,6 @@ static int smu_v13_0_6_post_init(struct smu_context *smu) return 0; } -static int mca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - - return smu_v13_0_6_mca_set_debug_mode(smu, enable); -} - -static int smu_v13_0_6_get_valid_mca_count(struct smu_context *smu, enum amdgpu_mca_error_type type, uint32_t *count) -{ - uint32_t msg; - int ret; - - if (!count) - return -EINVAL; - - switch (type) { - case AMDGPU_MCA_ERROR_TYPE_UE: - msg = SMU_MSG_QueryValidMcaCount; - break; - case AMDGPU_MCA_ERROR_TYPE_CE: - msg = SMU_MSG_QueryValidMcaCeCount; - break; - default: - return -EINVAL; - } - - ret = smu_cmn_send_smc_msg(smu, msg, count); - if (ret) { - *count = 0; - return ret; - } - - return 0; -} - -static int __smu_v13_0_6_mca_dump_bank(struct smu_context *smu, enum amdgpu_mca_error_type type, - int idx, int offset, uint32_t *val) -{ - uint32_t msg, param; - - switch (type) { - case AMDGPU_MCA_ERROR_TYPE_UE: - msg = SMU_MSG_McaBankDumpDW; - break; - case AMDGPU_MCA_ERROR_TYPE_CE: - msg = SMU_MSG_McaBankCeDumpDW; - break; - default: - return -EINVAL; - } - - param = ((idx & 0xffff) << 16) | (offset & 0xfffc); - - return smu_cmn_send_smc_msg_with_param(smu, msg, param, val); -} - -static int smu_v13_0_6_mca_dump_bank(struct smu_context *smu, enum amdgpu_mca_error_type type, - int idx, int offset, uint32_t *val, int count) -{ - int ret, i; - - if (!val) - return -EINVAL; - - for (i = 0; i < count; i++) { - ret = __smu_v13_0_6_mca_dump_bank(smu, type, idx, offset + (i << 2), &val[i]); - if (ret) - return ret; - } - - return 0; -} - -static const struct mca_bank_ipid smu_v13_0_6_mca_ipid_table[AMDGPU_MCA_IP_COUNT] = { - MCA_BANK_IPID(UMC, 0x96, 0x0), - MCA_BANK_IPID(SMU, 0x01, 0x1), - MCA_BANK_IPID(MP5, 0x01, 0x2), - MCA_BANK_IPID(PCS_XGMI, 0x50, 0x0), -}; - -static void mca_bank_entry_info_decode(struct mca_bank_entry *entry, struct mca_bank_info *info) -{ - u64 ipid = entry->regs[MCA_REG_IDX_IPID]; - u32 instidhi, instid; - - /* NOTE: All MCA IPID register share the same format, - * so the driver can share the MCMP1 register header file. - * */ - - info->hwid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, HardwareID); - info->mcatype = REG_GET_FIELD(ipid, MCMP1_IPIDT0, McaType); - - /* - * Unfied DieID Format: SAASS. A:AID, S:Socket. - * Unfied DieID[4] = InstanceId[0] - * Unfied DieID[0:3] = InstanceIdHi[0:3] - */ - instidhi = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdHi); - instid = REG_GET_FIELD(ipid, MCMP1_IPIDT0, InstanceIdLo); - info->aid = ((instidhi >> 2) & 0x03); - info->socket_id = ((instid & 0x1) << 2) | (instidhi & 0x03); -} - -static int mca_bank_read_reg(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, - int idx, int reg_idx, uint64_t *val) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - uint32_t data[2] = {0, 0}; - int ret; - - if (!val || reg_idx >= MCA_REG_IDX_COUNT) - return -EINVAL; - - ret = smu_v13_0_6_mca_dump_bank(smu, type, idx, reg_idx * 8, data, ARRAY_SIZE(data)); - if (ret) - return ret; - - *val = (uint64_t)data[1] << 32 | data[0]; - - dev_dbg(adev->dev, "mca read bank reg: type:%s, index: %d, reg_idx: %d, val: 0x%016llx\n", - type == AMDGPU_MCA_ERROR_TYPE_UE ? "UE" : "CE", idx, reg_idx, *val); - - return 0; -} - -static int mca_get_mca_entry(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, - int idx, struct mca_bank_entry *entry) -{ - int i, ret; - - /* NOTE: populated all mca register by default */ - for (i = 0; i < ARRAY_SIZE(entry->regs); i++) { - ret = mca_bank_read_reg(adev, type, idx, i, &entry->regs[i]); - if (ret) - return ret; - } - - entry->idx = idx; - entry->type = type; - - mca_bank_entry_info_decode(entry, &entry->info); - - return 0; -} - -static int mca_decode_ipid_to_hwip(uint64_t val) -{ - const struct mca_bank_ipid *ipid; - uint16_t hwid, mcatype; - int i; - - hwid = REG_GET_FIELD(val, MCMP1_IPIDT0, HardwareID); - mcatype = REG_GET_FIELD(val, MCMP1_IPIDT0, McaType); - - for (i = 0; i < ARRAY_SIZE(smu_v13_0_6_mca_ipid_table); i++) { - ipid = &smu_v13_0_6_mca_ipid_table[i]; - - if (!ipid->hwid) - continue; - - if (ipid->hwid == hwid && ipid->mcatype == mcatype) - return i; - } - - return AMDGPU_MCA_IP_UNKNOW; -} - -static int mca_umc_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count) -{ - uint64_t status0; - uint32_t ext_error_code; - uint32_t odecc_err_cnt; - - status0 = entry->regs[MCA_REG_IDX_STATUS]; - ext_error_code = MCA_REG__STATUS__ERRORCODEEXT(status0); - odecc_err_cnt = MCA_REG__MISC0__ERRCNT(entry->regs[MCA_REG_IDX_MISC0]); - - if (!REG_GET_FIELD(status0, MCMP1_STATUST0, Val)) { - *count = 0; - return 0; - } - - if (umc_v12_0_is_deferred_error(adev, status0) || - umc_v12_0_is_uncorrectable_error(adev, status0) || - umc_v12_0_is_correctable_error(adev, status0)) - *count = (ext_error_code == 0) ? odecc_err_cnt : 1; - - amdgpu_umc_update_ecc_status(adev, - entry->regs[MCA_REG_IDX_STATUS], - entry->regs[MCA_REG_IDX_IPID], - entry->regs[MCA_REG_IDX_ADDR]); - - return 0; -} - -static int mca_pcs_xgmi_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, - uint32_t *count) -{ - u32 ext_error_code; - u32 err_cnt; - - ext_error_code = MCA_REG__STATUS__ERRORCODEEXT(entry->regs[MCA_REG_IDX_STATUS]); - err_cnt = MCA_REG__MISC0__ERRCNT(entry->regs[MCA_REG_IDX_MISC0]); - - if (type == AMDGPU_MCA_ERROR_TYPE_UE && - (ext_error_code == 0 || ext_error_code == 9)) - *count = err_cnt; - else if (type == AMDGPU_MCA_ERROR_TYPE_CE && ext_error_code == 6) - *count = err_cnt; - - return 0; -} - -static bool mca_smu_check_error_code(struct amdgpu_device *adev, const struct mca_ras_info *mca_ras, - uint32_t errcode) -{ - int i; - - if (!mca_ras->err_code_count || !mca_ras->err_code_array) - return true; - - for (i = 0; i < mca_ras->err_code_count; i++) { - if (errcode == mca_ras->err_code_array[i]) - return true; - } - - return false; -} - -static int mca_gfx_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count) -{ - uint64_t status0, misc0; - - status0 = entry->regs[MCA_REG_IDX_STATUS]; - if (!REG_GET_FIELD(status0, MCMP1_STATUST0, Val)) { - *count = 0; - return 0; - } - - if (type == AMDGPU_MCA_ERROR_TYPE_UE && - REG_GET_FIELD(status0, MCMP1_STATUST0, UC) == 1 && - REG_GET_FIELD(status0, MCMP1_STATUST0, PCC) == 1) { - *count = 1; - return 0; - } else { - misc0 = entry->regs[MCA_REG_IDX_MISC0]; - *count = REG_GET_FIELD(misc0, MCMP1_MISC0T0, ErrCnt); - } - - return 0; -} - -static int mca_smu_mca_get_err_count(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry, uint32_t *count) -{ - uint64_t status0, misc0; - - status0 = entry->regs[MCA_REG_IDX_STATUS]; - if (!REG_GET_FIELD(status0, MCMP1_STATUST0, Val)) { - *count = 0; - return 0; - } - - if (type == AMDGPU_MCA_ERROR_TYPE_UE && - REG_GET_FIELD(status0, MCMP1_STATUST0, UC) == 1 && - REG_GET_FIELD(status0, MCMP1_STATUST0, PCC) == 1) { - if (count) - *count = 1; - return 0; - } - - misc0 = entry->regs[MCA_REG_IDX_MISC0]; - *count = REG_GET_FIELD(misc0, MCMP1_MISC0T0, ErrCnt); - - return 0; -} - -static bool mca_gfx_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry) -{ - uint32_t instlo; - - instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo); - instlo &= GENMASK(31, 1); - switch (instlo) { - case 0x36430400: /* SMNAID XCD 0 */ - case 0x38430400: /* SMNAID XCD 1 */ - case 0x40430400: /* SMNXCD XCD 0, NOTE: FIXME: fix this error later */ - return true; - default: - return false; - } - - return false; -}; - -static bool mca_smu_bank_is_valid(const struct mca_ras_info *mca_ras, struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - uint32_t errcode, instlo; - - instlo = REG_GET_FIELD(entry->regs[MCA_REG_IDX_IPID], MCMP1_IPIDT0, InstanceIdLo); - instlo &= GENMASK(31, 1); - if (instlo != 0x03b30400) - return false; - - if (smu_v13_0_6_cap_supported(smu, SMU_CAP(ACA_SYND))) { - errcode = MCA_REG__SYND__ERRORINFORMATION(entry->regs[MCA_REG_IDX_SYND]); - errcode &= 0xff; - } else { - errcode = REG_GET_FIELD(entry->regs[MCA_REG_IDX_STATUS], MCMP1_STATUST0, ErrorCode); - } - - return mca_smu_check_error_code(adev, mca_ras, errcode); -} - -static int sdma_err_codes[] = { CODE_SDMA0, CODE_SDMA1, CODE_SDMA2, CODE_SDMA3 }; -static int mmhub_err_codes[] = { - CODE_DAGB0, CODE_DAGB0 + 1, CODE_DAGB0 + 2, CODE_DAGB0 + 3, CODE_DAGB0 + 4, /* DAGB0-4 */ - CODE_EA0, CODE_EA0 + 1, CODE_EA0 + 2, CODE_EA0 + 3, CODE_EA0 + 4, /* MMEA0-4*/ - CODE_VML2, CODE_VML2_WALKER, CODE_MMCANE, -}; - -static int vcn_err_codes[] = { - CODE_VIDD, CODE_VIDV, -}; -static int jpeg_err_codes[] = { - CODE_JPEG0S, CODE_JPEG0D, CODE_JPEG1S, CODE_JPEG1D, - CODE_JPEG2S, CODE_JPEG2D, CODE_JPEG3S, CODE_JPEG3D, - CODE_JPEG4S, CODE_JPEG4D, CODE_JPEG5S, CODE_JPEG5D, - CODE_JPEG6S, CODE_JPEG6D, CODE_JPEG7S, CODE_JPEG7D, -}; - -static const struct mca_ras_info mca_ras_table[] = { - { - .blkid = AMDGPU_RAS_BLOCK__UMC, - .ip = AMDGPU_MCA_IP_UMC, - .get_err_count = mca_umc_mca_get_err_count, - }, { - .blkid = AMDGPU_RAS_BLOCK__GFX, - .ip = AMDGPU_MCA_IP_SMU, - .get_err_count = mca_gfx_mca_get_err_count, - .bank_is_valid = mca_gfx_smu_bank_is_valid, - }, { - .blkid = AMDGPU_RAS_BLOCK__SDMA, - .ip = AMDGPU_MCA_IP_SMU, - .err_code_array = sdma_err_codes, - .err_code_count = ARRAY_SIZE(sdma_err_codes), - .get_err_count = mca_smu_mca_get_err_count, - .bank_is_valid = mca_smu_bank_is_valid, - }, { - .blkid = AMDGPU_RAS_BLOCK__MMHUB, - .ip = AMDGPU_MCA_IP_SMU, - .err_code_array = mmhub_err_codes, - .err_code_count = ARRAY_SIZE(mmhub_err_codes), - .get_err_count = mca_smu_mca_get_err_count, - .bank_is_valid = mca_smu_bank_is_valid, - }, { - .blkid = AMDGPU_RAS_BLOCK__XGMI_WAFL, - .ip = AMDGPU_MCA_IP_PCS_XGMI, - .get_err_count = mca_pcs_xgmi_mca_get_err_count, - }, { - .blkid = AMDGPU_RAS_BLOCK__VCN, - .ip = AMDGPU_MCA_IP_SMU, - .err_code_array = vcn_err_codes, - .err_code_count = ARRAY_SIZE(vcn_err_codes), - .get_err_count = mca_smu_mca_get_err_count, - .bank_is_valid = mca_smu_bank_is_valid, - }, { - .blkid = AMDGPU_RAS_BLOCK__JPEG, - .ip = AMDGPU_MCA_IP_SMU, - .err_code_array = jpeg_err_codes, - .err_code_count = ARRAY_SIZE(jpeg_err_codes), - .get_err_count = mca_smu_mca_get_err_count, - .bank_is_valid = mca_smu_bank_is_valid, - }, -}; - -static const struct mca_ras_info *mca_get_mca_ras_info(struct amdgpu_device *adev, enum amdgpu_ras_block blkid) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mca_ras_table); i++) { - if (mca_ras_table[i].blkid == blkid) - return &mca_ras_table[i]; - } - - return NULL; -} - -static int mca_get_valid_mca_count(struct amdgpu_device *adev, enum amdgpu_mca_error_type type, uint32_t *count) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - int ret; - - switch (type) { - case AMDGPU_MCA_ERROR_TYPE_UE: - case AMDGPU_MCA_ERROR_TYPE_CE: - ret = smu_v13_0_6_get_valid_mca_count(smu, type, count); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static bool mca_bank_is_valid(struct amdgpu_device *adev, const struct mca_ras_info *mca_ras, - enum amdgpu_mca_error_type type, struct mca_bank_entry *entry) -{ - if (mca_decode_ipid_to_hwip(entry->regs[MCA_REG_IDX_IPID]) != mca_ras->ip) - return false; - - if (mca_ras->bank_is_valid) - return mca_ras->bank_is_valid(mca_ras, adev, type, entry); - - return true; -} - -static int mca_smu_parse_mca_error_count(struct amdgpu_device *adev, enum amdgpu_ras_block blk, enum amdgpu_mca_error_type type, - struct mca_bank_entry *entry, uint32_t *count) -{ - const struct mca_ras_info *mca_ras; - - if (!entry || !count) - return -EINVAL; - - mca_ras = mca_get_mca_ras_info(adev, blk); - if (!mca_ras) - return -EOPNOTSUPP; - - if (!mca_bank_is_valid(adev, mca_ras, type, entry)) { - *count = 0; - return 0; - } - - return mca_ras->get_err_count(mca_ras, adev, type, entry, count); -} - -static int mca_smu_get_mca_entry(struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, int idx, struct mca_bank_entry *entry) -{ - return mca_get_mca_entry(adev, type, idx, entry); -} - -static int mca_smu_get_valid_mca_count(struct amdgpu_device *adev, - enum amdgpu_mca_error_type type, uint32_t *count) -{ - return mca_get_valid_mca_count(adev, type, count); -} - -static const struct amdgpu_mca_smu_funcs smu_v13_0_6_mca_smu_funcs = { - .max_ue_count = 12, - .max_ce_count = 12, - .mca_set_debug_mode = mca_smu_set_debug_mode, - .mca_parse_mca_error_count = mca_smu_parse_mca_error_count, - .mca_get_mca_entry = mca_smu_get_mca_entry, - .mca_get_valid_mca_count = mca_smu_get_valid_mca_count, -}; - -static int aca_smu_set_debug_mode(struct amdgpu_device *adev, bool enable) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - - return smu_v13_0_6_mca_set_debug_mode(smu, enable); -} - -static int smu_v13_0_6_get_valid_aca_count(struct smu_context *smu, enum aca_smu_type type, u32 *count) -{ - uint32_t msg; - int ret; - - if (!count) - return -EINVAL; - - switch (type) { - case ACA_SMU_TYPE_UE: - msg = SMU_MSG_QueryValidMcaCount; - break; - case ACA_SMU_TYPE_CE: - msg = SMU_MSG_QueryValidMcaCeCount; - break; - default: - return -EINVAL; - } - - ret = smu_cmn_send_smc_msg(smu, msg, count); - if (ret) { - *count = 0; - return ret; - } - - return 0; -} - -static int aca_smu_get_valid_aca_count(struct amdgpu_device *adev, - enum aca_smu_type type, u32 *count) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - int ret; - - switch (type) { - case ACA_SMU_TYPE_UE: - case ACA_SMU_TYPE_CE: - ret = smu_v13_0_6_get_valid_aca_count(smu, type, count); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int __smu_v13_0_6_aca_bank_dump(struct smu_context *smu, enum aca_smu_type type, - int idx, int offset, u32 *val) -{ - uint32_t msg, param; - - switch (type) { - case ACA_SMU_TYPE_UE: - msg = SMU_MSG_McaBankDumpDW; - break; - case ACA_SMU_TYPE_CE: - msg = SMU_MSG_McaBankCeDumpDW; - break; - default: - return -EINVAL; - } - - param = ((idx & 0xffff) << 16) | (offset & 0xfffc); - - return smu_cmn_send_smc_msg_with_param(smu, msg, param, (uint32_t *)val); -} - -static int smu_v13_0_6_aca_bank_dump(struct smu_context *smu, enum aca_smu_type type, - int idx, int offset, u32 *val, int count) -{ - int ret, i; - - if (!val) - return -EINVAL; - - for (i = 0; i < count; i++) { - ret = __smu_v13_0_6_aca_bank_dump(smu, type, idx, offset + (i << 2), &val[i]); - if (ret) - return ret; - } - - return 0; -} - -static int aca_bank_read_reg(struct amdgpu_device *adev, enum aca_smu_type type, - int idx, int reg_idx, u64 *val) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - u32 data[2] = {0, 0}; - int ret; - - if (!val || reg_idx >= ACA_REG_IDX_COUNT) - return -EINVAL; - - ret = smu_v13_0_6_aca_bank_dump(smu, type, idx, reg_idx * 8, data, ARRAY_SIZE(data)); - if (ret) - return ret; - - *val = (u64)data[1] << 32 | data[0]; - - dev_dbg(adev->dev, "mca read bank reg: type:%s, index: %d, reg_idx: %d, val: 0x%016llx\n", - type == ACA_SMU_TYPE_UE ? "UE" : "CE", idx, reg_idx, *val); - - return 0; -} - -static int aca_smu_get_valid_aca_bank(struct amdgpu_device *adev, - enum aca_smu_type type, int idx, struct aca_bank *bank) -{ - int i, ret, count; - - count = min_t(int, 16, ARRAY_SIZE(bank->regs)); - for (i = 0; i < count; i++) { - ret = aca_bank_read_reg(adev, type, idx, i, &bank->regs[i]); - if (ret) - return ret; - } - - return 0; -} - -static int aca_smu_parse_error_code(struct amdgpu_device *adev, struct aca_bank *bank) -{ - struct smu_context *smu = adev->powerplay.pp_handle; - int error_code; - - if (smu_v13_0_6_cap_supported(smu, SMU_CAP(ACA_SYND))) - error_code = ACA_REG__SYND__ERRORINFORMATION(bank->regs[ACA_REG_IDX_SYND]); - else - error_code = ACA_REG__STATUS__ERRORCODE(bank->regs[ACA_REG_IDX_STATUS]); - - return error_code & 0xff; -} - -static const struct aca_smu_funcs smu_v13_0_6_aca_smu_funcs = { - .max_ue_bank_count = 12, - .max_ce_bank_count = 12, - .set_debug_mode = aca_smu_set_debug_mode, - .get_valid_aca_count = aca_smu_get_valid_aca_count, - .get_valid_aca_bank = aca_smu_get_valid_aca_bank, - .parse_error_code = aca_smu_parse_error_code, -}; - static void smu_v13_0_6_set_temp_funcs(struct smu_context *smu) { smu->smu_temp.temp_funcs = (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) @@ -3929,9 +3281,6 @@ static int smu_v13_0_6_get_ras_smu_drv(struct smu_context *smu, const struct ras if (amdgpu_sriov_vf(smu->adev)) return -EOPNOTSUPP; - if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_HROM_EN_BIT)) - smu_v13_0_6_cap_set(smu, SMU_CAP(RAS_EEPROM)); - switch (amdgpu_ip_version(smu->adev, MP1_HWIP, 0)) { case IP_VERSION(13, 0, 12): *ras_smu_drv = &smu_v13_0_12_ras_smu_drv; @@ -4020,7 +3369,5 @@ void smu_v13_0_6_set_ppt_funcs(struct smu_context *smu) smu->smc_fw_caps |= SMU_FW_CAP_RAS_PRI; smu_v13_0_init_msg_ctl(smu, message_map); smu_v13_0_6_set_temp_funcs(smu); - amdgpu_mca_smu_init_funcs(smu->adev, &smu_v13_0_6_mca_smu_funcs); - amdgpu_aca_set_smu_funcs(smu->adev, &smu_v13_0_6_aca_smu_funcs); } diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index 0f774b0920ce..5f23f2e7f401 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -2385,15 +2385,16 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, uint32_t pp_limit = smu->adev->pm.ac_power ? skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] : skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0]; - uint32_t power_limit = 0, od_percent_upper = 0, od_percent_lower = 0; + uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC]; + uint32_t min_limit = min_t(uint32_t, pp_limit, msg_limit); + uint32_t max_limit = max_t(uint32_t, pp_limit, msg_limit); + uint32_t od_percent_upper = 0, od_percent_lower = 0; int ret; if (current_power_limit) { - ret = smu_v13_0_get_current_power_limit(smu, &power_limit); + ret = smu_v13_0_get_current_power_limit(smu, current_power_limit); if (ret) - power_limit = pp_limit; - - *current_power_limit = power_limit; + *current_power_limit = pp_limit; } if (default_power_limit) @@ -2414,12 +2415,12 @@ static int smu_v13_0_7_get_power_limit(struct smu_context *smu, od_percent_upper, od_percent_lower, pp_limit); if (max_power_limit) { - *max_power_limit = pp_limit * (100 + od_percent_upper); + *max_power_limit = max_limit * (100 + od_percent_upper); *max_power_limit /= 100; } if (min_power_limit) { - *min_power_limit = pp_limit * (100 - od_percent_lower); + *min_power_limit = min_limit * (100 - od_percent_lower); *min_power_limit /= 100; } @@ -2573,9 +2574,10 @@ static int smu_v13_0_7_set_power_profile_mode(struct smu_context *smu, return -ENOMEM; } if (custom_params && custom_params_max_idx) { - if (custom_params_max_idx != SMU_13_0_7_CUSTOM_PARAMS_COUNT) - return -EINVAL; - if (custom_params[0] >= SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT) + if (!smu_cmn_custom_params_count_valid(custom_params_max_idx, + SMU_13_0_7_CUSTOM_PARAMS_COUNT) || + !smu_cmn_custom_params_clock_valid(custom_params[0], + SMU_13_0_7_CUSTOM_PARAMS_CLOCK_COUNT)) return -EINVAL; idx = custom_params[0] * SMU_13_0_7_CUSTOM_PARAMS_COUNT; smu->custom_profile_params[idx] = 1; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index d0a8df1aa6b6..2a0c7cde938d 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -194,7 +194,7 @@ int smu_v14_0_init_pptable_microcode(struct smu_context *smu) if (!pptable_id) return 0; - ret = smu_v14_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id); if (ret) return ret; @@ -229,48 +229,6 @@ int smu_v14_0_check_fw_status(struct smu_context *smu) return -EIO; } -static int smu_v14_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t ppt_offset_bytes; - const struct smc_firmware_header_v2_0 *v2; - - v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data; - - ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes); - *size = le32_to_cpu(v2->ppt_size_bytes); - *table = (uint8_t *)v2 + ppt_offset_bytes; - - return 0; -} - -static int smu_v14_0_set_pptable_v2_1(struct smu_context *smu, void **table, - uint32_t *size, uint32_t pptable_id) -{ - struct amdgpu_device *adev = smu->adev; - const struct smc_firmware_header_v2_1 *v2_1; - struct smc_soft_pptable_entry *entries; - uint32_t pptable_count = 0; - int i = 0; - - v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data; - entries = (struct smc_soft_pptable_entry *) - ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset)); - pptable_count = le32_to_cpu(v2_1->pptable_count); - for (i = 0; i < pptable_count; i++) { - if (le32_to_cpu(entries[i].id) == pptable_id) { - *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes)); - *size = le32_to_cpu(entries[i].ppt_size_bytes); - break; - } - } - - if (i == pptable_count) - return -EINVAL; - - return 0; -} - static int smu_v14_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -293,45 +251,6 @@ static int smu_v14_0_get_pptable_from_vbios(struct smu_context *smu, void **tabl return 0; } -int smu_v14_0_get_pptable_from_firmware(struct smu_context *smu, - void **table, - uint32_t *size, - uint32_t pptable_id) -{ - const struct smc_firmware_header_v1_0 *hdr; - struct amdgpu_device *adev = smu->adev; - uint16_t version_major, version_minor; - int ret; - - hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; - if (!hdr) - return -EINVAL; - - dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id); - - version_major = le16_to_cpu(hdr->header.header_version_major); - version_minor = le16_to_cpu(hdr->header.header_version_minor); - if (version_major != 2) { - dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n", - version_major, version_minor); - return -EINVAL; - } - - switch (version_minor) { - case 0: - ret = smu_v14_0_set_pptable_v2_0(smu, table, size); - break; - case 1: - ret = smu_v14_0_set_pptable_v2_1(smu, table, size, pptable_id); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - int smu_v14_0_setup_pptable(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -351,7 +270,7 @@ int smu_v14_0_setup_pptable(struct smu_context *smu) if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1)) ret = smu_v14_0_get_pptable_from_vbios(smu, &table, &size); else - ret = smu_v14_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index fdc1456b885c..d6cf643205ab 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -1828,9 +1828,10 @@ static int smu_v14_0_2_set_power_profile_mode(struct smu_context *smu, return -ENOMEM; } if (custom_params && custom_params_max_idx) { - if (custom_params_max_idx != SMU_14_0_2_CUSTOM_PARAMS_COUNT) - return -EINVAL; - if (custom_params[0] >= SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT) + if (!smu_cmn_custom_params_count_valid(custom_params_max_idx, + SMU_14_0_2_CUSTOM_PARAMS_COUNT) || + !smu_cmn_custom_params_clock_valid(custom_params[0], + SMU_14_0_2_CUSTOM_PARAMS_CLOCK_COUNT)) return -EINVAL; idx = custom_params[0] * SMU_14_0_2_CUSTOM_PARAMS_COUNT; smu->custom_profile_params[idx] = 1; @@ -2889,8 +2890,6 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = { .deep_sleep_control = smu_v14_0_deep_sleep_control, .gfx_ulv_control = smu_v14_0_gfx_ulv_control, .get_bamaco_support = smu_v14_0_get_bamaco_support, - .baco_get_state = smu_v14_0_baco_get_state, - .baco_set_state = smu_v14_0_baco_set_state, .baco_enter = smu_v14_0_2_baco_enter, .baco_exit = smu_v14_0_2_baco_exit, .mode1_reset_is_support = smu_v14_0_2_is_mode1_reset_supported, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c index a1318409e4b5..f3fb6ed4bc95 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu15/smu_v15_0.c @@ -174,7 +174,7 @@ int smu_v15_0_init_pptable_microcode(struct smu_context *smu) if (!pptable_id) return 0; - ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id); if (ret) return ret; @@ -207,48 +207,6 @@ int smu_v15_0_check_fw_status(struct smu_context *smu) return -EIO; } -static int smu_v15_0_set_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t ppt_offset_bytes; - const struct smc_firmware_header_v2_0 *v2; - - v2 = (const struct smc_firmware_header_v2_0 *) adev->pm.fw->data; - - ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes); - *size = le32_to_cpu(v2->ppt_size_bytes); - *table = (uint8_t *)v2 + ppt_offset_bytes; - - return 0; -} - -static int smu_v15_0_set_pptable_v2_1(struct smu_context *smu, void **table, - uint32_t *size, uint32_t pptable_id) -{ - struct amdgpu_device *adev = smu->adev; - const struct smc_firmware_header_v2_1 *v2_1; - struct smc_soft_pptable_entry *entries; - uint32_t pptable_count = 0; - int i = 0; - - v2_1 = (const struct smc_firmware_header_v2_1 *) adev->pm.fw->data; - entries = (struct smc_soft_pptable_entry *) - ((uint8_t *)v2_1 + le32_to_cpu(v2_1->pptable_entry_offset)); - pptable_count = le32_to_cpu(v2_1->pptable_count); - for (i = 0; i < pptable_count; i++) { - if (le32_to_cpu(entries[i].id) == pptable_id) { - *table = ((uint8_t *)v2_1 + le32_to_cpu(entries[i].ppt_offset_bytes)); - *size = le32_to_cpu(entries[i].ppt_size_bytes); - break; - } - } - - if (i == pptable_count) - return -EINVAL; - - return 0; -} - static int smu_v15_0_get_pptable_from_vbios(struct smu_context *smu, void **table, uint32_t *size) { struct amdgpu_device *adev = smu->adev; @@ -271,45 +229,6 @@ static int smu_v15_0_get_pptable_from_vbios(struct smu_context *smu, void **tabl return 0; } -int smu_v15_0_get_pptable_from_firmware(struct smu_context *smu, - void **table, - uint32_t *size, - uint32_t pptable_id) -{ - const struct smc_firmware_header_v1_0 *hdr; - struct amdgpu_device *adev = smu->adev; - uint16_t version_major, version_minor; - int ret; - - hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; - if (!hdr) - return -EINVAL; - - dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id); - - version_major = le16_to_cpu(hdr->header.header_version_major); - version_minor = le16_to_cpu(hdr->header.header_version_minor); - if (version_major != 2) { - dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n", - version_major, version_minor); - return -EINVAL; - } - - switch (version_minor) { - case 0: - ret = smu_v15_0_set_pptable_v2_0(smu, table, size); - break; - case 1: - ret = smu_v15_0_set_pptable_v2_1(smu, table, size, pptable_id); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - int smu_v15_0_setup_pptable(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -329,7 +248,7 @@ int smu_v15_0_setup_pptable(struct smu_context *smu) if ((amdgpu_sriov_vf(adev) || !pptable_id) && (amdgpu_emu_mode != 1)) ret = smu_v15_0_get_pptable_from_vbios(smu, &table, &size); else - ret = smu_v15_0_get_pptable_from_firmware(smu, &table, &size, pptable_id); + ret = smu_cmn_get_pptable_from_firmware(smu, &table, &size, pptable_id); if (ret) return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c index d365f06ac1ac..2bd3ea17e789 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c @@ -1544,3 +1544,143 @@ int smu_cmn_dpm_pcie_width_idx(int width) return ret; } + +static int smu_cmn_get_pptable_v2_0(struct smu_context *smu, void **table, uint32_t *size) +{ + const struct smc_firmware_header_v2_0 *v2; + struct amdgpu_device *adev = smu->adev; + size_t fw_size = adev->pm.fw->size; + uint32_t ppt_offset_bytes; + uint32_t ppt_size_bytes; + + if (fw_size < sizeof(*v2)) { + dev_err(adev->dev, + "SMC firmware too small for v2.0 header: %zu < %zu\n", + fw_size, sizeof(*v2)); + return -EINVAL; + } + + v2 = (const struct smc_firmware_header_v2_0 *)adev->pm.fw->data; + + ppt_offset_bytes = le32_to_cpu(v2->ppt_offset_bytes); + ppt_size_bytes = le32_to_cpu(v2->ppt_size_bytes); + + if (ppt_offset_bytes > fw_size || + ppt_size_bytes > fw_size - ppt_offset_bytes) { + dev_err(adev->dev, + "pptable v2.0 exceeds firmware binary: offset %u + size %u > %zu\n", + ppt_offset_bytes, ppt_size_bytes, fw_size); + return -EINVAL; + } + + *size = ppt_size_bytes; + *table = (uint8_t *)v2 + ppt_offset_bytes; + + return 0; +} + +static int smu_cmn_get_pptable_v2_1(struct smu_context *smu, void **table, + uint32_t *size, uint32_t pptable_id) +{ + const struct smc_firmware_header_v2_1 *v2_1; + struct amdgpu_device *adev = smu->adev; + struct smc_soft_pptable_entry *entries; + size_t fw_size = adev->pm.fw->size; + uint32_t pptable_entry_offset; + uint32_t ppt_offset_bytes; + uint32_t ppt_size_bytes; + uint32_t pptable_count; + int i; + + if (fw_size < sizeof(*v2_1)) { + dev_err(adev->dev, + "SMC firmware too small for v2.1 header: %zu < %zu\n", + fw_size, sizeof(*v2_1)); + return -EINVAL; + } + + v2_1 = (const struct smc_firmware_header_v2_1 *)adev->pm.fw->data; + + pptable_entry_offset = le32_to_cpu(v2_1->pptable_entry_offset); + pptable_count = le32_to_cpu(v2_1->pptable_count); + + if (pptable_entry_offset > fw_size || + pptable_count > (fw_size - pptable_entry_offset) / sizeof(*entries)) { + dev_err(adev->dev, + "pptable v2.1 entry array exceeds firmware binary: offset %u, count %u\n", + pptable_entry_offset, pptable_count); + return -EINVAL; + } + + entries = (struct smc_soft_pptable_entry *) + ((uint8_t *)v2_1 + pptable_entry_offset); + + for (i = 0; i < pptable_count; i++) { + if (le32_to_cpu(entries[i].id) != pptable_id) + continue; + + ppt_offset_bytes = le32_to_cpu(entries[i].ppt_offset_bytes); + ppt_size_bytes = le32_to_cpu(entries[i].ppt_size_bytes); + + if (ppt_offset_bytes > fw_size || + ppt_size_bytes > fw_size - ppt_offset_bytes) { + dev_err(adev->dev, + "pptable entry %d exceeds firmware binary: offset %u + size %u > %zu\n", + i, ppt_offset_bytes, ppt_size_bytes, fw_size); + return -EINVAL; + } + + *table = (uint8_t *)v2_1 + ppt_offset_bytes; + *size = ppt_size_bytes; + return 0; + } + + return -EINVAL; +} + +/** + * smu_cmn_get_pptable_from_firmware - locate the soft pptable embedded in the + * SMC firmware binary. + * @smu: SMU context + * @table: on success, set to the start of the pptable within the firmware + * blob + * @size: on success, set to the pptable size in bytes + * @pptable_id: the entry ID to search for (used only for v2.1 binaries) + * + * Reads the firmware header version and dispatches to the appropriate v2.x + * parser. Only major version 2 is supported; minor version selects between + * the single-entry (v2.0) and multi-entry directory (v2.1) layouts. + * + * Return: 0 on success, -EINVAL for an unsupported version or if the + * requested pptable cannot be found or exceeds the binary bounds. + */ +int smu_cmn_get_pptable_from_firmware(struct smu_context *smu, void **table, + uint32_t *size, uint32_t pptable_id) +{ + const struct smc_firmware_header_v1_0 *hdr; + struct amdgpu_device *adev = smu->adev; + uint16_t version_major, version_minor; + + hdr = (const struct smc_firmware_header_v1_0 *)adev->pm.fw->data; + if (!hdr) + return -EINVAL; + + dev_info(adev->dev, "use driver provided pptable %d\n", pptable_id); + + version_major = le16_to_cpu(hdr->header.header_version_major); + version_minor = le16_to_cpu(hdr->header.header_version_minor); + if (version_major != 2) { + dev_err(adev->dev, "Unsupported smu firmware version %d.%d\n", + version_major, version_minor); + return -EINVAL; + } + + switch (version_minor) { + case 0: + return smu_cmn_get_pptable_v2_0(smu, table, size); + case 1: + return smu_cmn_get_pptable_v2_1(smu, table, size, pptable_id); + default: + return -EINVAL; + } +} diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h index 0e119965ce13..ae6742f5298f 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h +++ b/drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h @@ -113,6 +113,16 @@ static inline int pcie_gen_to_speed(uint32_t gen) return ((gen == 0) ? link_speed[0] : link_speed[gen - 1]); } +static inline bool smu_cmn_custom_params_count_valid(u32 max_idx, u32 params_count) +{ + return max_idx == params_count; +} + +static inline bool smu_cmn_custom_params_clock_valid(long clock_idx, long clock_count) +{ + return clock_idx >= 0 && clock_idx < clock_count; +} + int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, enum smu_message_type msg, uint32_t param, @@ -239,6 +249,9 @@ int smu_cmn_dpm_pcie_gen_idx(int gen); int smu_cmn_dpm_pcie_width_idx(int width); int smu_cmn_check_fw_version(struct smu_context *smu); +int smu_cmn_get_pptable_from_firmware(struct smu_context *smu, void **table, + uint32_t *size, uint32_t pptable_id); + /*SMU gpu metrics */ /* Attribute ID mapping */ diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c index 658bf3fdb66b..bfbfdffbfbe6 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_cmd.c @@ -30,9 +30,6 @@ #include "amdgpu_ras_mgr.h" #include "amdgpu_virt_ras_cmd.h" -/* inject address is 52 bits */ -#define RAS_UMC_INJECT_ADDR_LIMIT (0x1ULL << 52) - #define AMDGPU_RAS_TYPE_RASCORE 0x1 #define AMDGPU_RAS_TYPE_AMDGPU 0x2 #define AMDGPU_RAS_TYPE_VF 0x3 diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_eeprom_i2c.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_eeprom_i2c.c index 3ed3ff42b7e1..9c6d0024210d 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_eeprom_i2c.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_eeprom_i2c.c @@ -67,7 +67,7 @@ static int ras_eeprom_i2c_config(struct ras_core_context *ras_core) struct ras_eeprom_control *control = &ras_core->ras_eeprom; u8 i2c_addr; - if (amdgpu_atomfirmware_ras_rom_addr(adev, &i2c_addr)) { + if (adev->bios && amdgpu_atomfirmware_ras_rom_addr(adev, &i2c_addr)) { /* The address given by VBIOS is an 8-bit, wire-format * address, i.e. the most significant byte. * diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c index a22d1aebbeb9..b62bbb5ea292 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.c @@ -95,11 +95,35 @@ static int amdgpu_ras_mgr_init_aca_config(struct amdgpu_device *adev, return 0; } +static uint64_t amdgpu_ras_mgr_reserved_vram_size(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + uint64_t reserved_pages_in_bytes = 0; + + if (!con || (adev->flags & AMD_IS_APU)) + return 0; + + switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) { + case IP_VERSION(13, 0, 6): + case IP_VERSION(13, 0, 12): + reserved_pages_in_bytes = RAS_RESERVED_VRAM_SIZE_DEFAULT; + break; + case IP_VERSION(13, 0, 14): + reserved_pages_in_bytes = (RAS_RESERVED_VRAM_SIZE_DEFAULT << 1); + break; + default: + break; + } + return reserved_pages_in_bytes; +} + static int amdgpu_ras_mgr_init_eeprom_config(struct amdgpu_device *adev, struct ras_core_config *config) { struct ras_eeprom_config *eeprom_cfg = &config->eeprom_cfg; + uint64_t ras_reserved_vram_size; + ras_reserved_vram_size = amdgpu_ras_mgr_reserved_vram_size(adev); eeprom_cfg->eeprom_sys_fn = &amdgpu_ras_eeprom_i2c_sys_func; eeprom_cfg->eeprom_i2c_adapter = adev->pm.ras_eeprom_i2c_bus; if (eeprom_cfg->eeprom_i2c_adapter) { @@ -133,7 +157,7 @@ static int amdgpu_ras_mgr_init_eeprom_config(struct amdgpu_device *adev, div64_u64(adev->gmc.mc_vram_size, TYPICAL_ECC_BAD_PAGE_RATE); else if (amdgpu_bad_page_threshold == WARN_NONSTOP_OVER_THRESHOLD) eeprom_cfg->eeprom_record_threshold_count = - COUNT_BAD_PAGE_THRESHOLD(RAS_RESERVED_VRAM_SIZE_DEFAULT); + COUNT_BAD_PAGE_THRESHOLD(ras_reserved_vram_size); else eeprom_cfg->eeprom_record_threshold_count = amdgpu_bad_page_threshold; @@ -142,6 +166,21 @@ static int amdgpu_ras_mgr_init_eeprom_config(struct amdgpu_device *adev, return 0; } +static bool amdgpu_ras_mgr_eeprom_is_supported(struct amdgpu_device *adev) +{ + if (amdgpu_sriov_vf(adev)) + return false; + + switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) { + case IP_VERSION(13, 0, 6): + case IP_VERSION(13, 0, 12): + case IP_VERSION(13, 0, 14): + return (adev->gmc.is_app_apu) ? false : true; + default: + return false; + } +} + static int amdgpu_ras_mgr_init_mp1_config(struct amdgpu_device *adev, struct ras_core_config *config) { @@ -266,7 +305,8 @@ static struct ras_core_context *amdgpu_ras_mgr_create_ras_core(struct amdgpu_dev init_config.aca_ip_version = IP_VERSION(1, 0, 0); init_config.sys_fn = &amdgpu_ras_sys_fn; - init_config.ras_eeprom_supported = true; + init_config.ras_eeprom_supported = + amdgpu_ras_mgr_eeprom_is_supported(adev); init_config.poison_supported = amdgpu_ras_is_poison_mode_supported(adev); @@ -425,6 +465,28 @@ static int amdgpu_ras_mgr_hw_fini(struct amdgpu_ip_block *ip_block) return 0; } +int amdgpu_ras_mgr_resume_after_reset(struct amdgpu_device *adev) +{ + struct amdgpu_ras *con = amdgpu_ras_get_context(adev); + struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev); + struct amdgpu_ip_block *ip_block; + + if (!con || !con->uniras_enabled) + return 0; + + if (!ras_mgr || !ras_mgr->ras_core) + return -EINVAL; + + if (ras_mgr->ras_is_ready) + return 0; + + ip_block = amdgpu_device_ip_get_ip_block(adev, AMD_IP_BLOCK_TYPE_RAS); + if (!ip_block) + return -EINVAL; + + return amdgpu_ras_mgr_hw_init(ip_block); +} + struct amdgpu_ras_mgr *amdgpu_ras_mgr_get_context(struct amdgpu_device *adev) { if (!adev || !adev->psp.ras_context.ras) @@ -733,3 +795,13 @@ int amdgpu_ras_mgr_lookup_bad_pages_in_a_row(struct amdgpu_device *adev, return ras_core_convert_soc_pa_to_cur_nps_pages(ras_mgr->ras_core, addr, nps_page_addr, max_page_count); } + +int amdgpu_ras_mgr_set_debug_mode(struct amdgpu_device *adev, bool enable) +{ + struct amdgpu_ras_mgr *ras_mgr = amdgpu_ras_mgr_get_context(adev); + + if (!ras_mgr || !ras_mgr->ras_core || !ras_mgr->ras_is_ready) + return false; + + return ras_core_set_debug_mode(ras_mgr->ras_core, enable); +} diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h index 4f44a917d48b..a20bb8fdce87 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mgr.h @@ -82,6 +82,8 @@ int amdgpu_ras_mgr_handle_ras_cmd(struct amdgpu_device *adev, void *output, uint32_t out_size); int amdgpu_ras_mgr_pre_reset(struct amdgpu_device *adev); int amdgpu_ras_mgr_post_reset(struct amdgpu_device *adev); +int amdgpu_ras_mgr_resume_after_reset(struct amdgpu_device *adev); int amdgpu_ras_mgr_lookup_bad_pages_in_a_row(struct amdgpu_device *adev, uint64_t addr, uint64_t *nps_page_addr, uint32_t max_page_count); +int amdgpu_ras_mgr_set_debug_mode(struct amdgpu_device *adev, bool enable); #endif diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c index 2098f24d4940..3c4575a5d902 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_mp1_v13_0.c @@ -24,6 +24,7 @@ #include "amdgpu_smu.h" #include "amdgpu_reset.h" #include "amdgpu_ras_mp1_v13_0.h" +#include "smu13_driver_if_v13_0_6.h" #define RAS_MP1_MSG_QueryValidMcaCeCount 0x3A #define RAS_MP1_MSG_McaBankCeDumpDW 0x3B @@ -131,10 +132,23 @@ static int mp1_v13_0_get_ras_enabled_mask(struct ras_core_context *ras_core, return ret; } +static int mp1_v13_0_set_debug_mode(struct ras_core_context *ras_core, bool enable) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; + int ret; + u32 smu_msg = SMU_MSG_ClearMcaOnRead; + + ret = amdgpu_smu_ras_send_msg(adev, smu_msg, + enable ? 0 : ClearMcaOnRead_UE_FLAG_MASK | + ClearMcaOnRead_CE_POLL_MASK, NULL); + return ret; +} + const struct ras_mp1_sys_func amdgpu_ras_mp1_sys_func_v13_0 = { .mp1_get_valid_bank_count = mp1_v13_0_get_valid_bank_count, .mp1_dump_valid_bank = mp1_v13_0_dump_valid_bank, .mp1_send_eeprom_msg = mp1_v13_0_eeprom_send_msg, .mp1_get_ras_enabled_mask = mp1_v13_0_get_ras_enabled_mask, + .mp1_set_debug_mode = mp1_v13_0_set_debug_mode, }; diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c index 7d728e523604..e4444798bc73 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c +++ b/drivers/gpu/drm/amd/ras/ras_mgr/amdgpu_ras_sys.c @@ -267,6 +267,24 @@ static int amdgpu_ras_sys_put_gpu_mem(struct ras_core_context *ras_core, return 0; } +static int amdgpu_ras_sys_check_address_sanity(struct ras_core_context *ras_core, + uint64_t addr) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)ras_core->dev; + + if ((addr >= adev->gmc.mc_vram_size && + adev->gmc.mc_vram_size) || + (addr >= RAS_UMC_INJECT_ADDR_LIMIT)) + return -EINVAL; + + if (addr >= adev->gmc.real_vram_size) { + RAS_DEV_WARN(ras_core->dev, "Recorded address out of range: 0x%llx!\n", addr); + return -EINVAL; + } + + return 0; +} + const struct ras_sys_func amdgpu_ras_sys_fn = { .ras_notifier = amdgpu_ras_sys_event_notifier, .get_utc_second_timestamp = amdgpu_ras_sys_get_utc_second_timestamp, @@ -277,4 +295,5 @@ const struct ras_sys_func amdgpu_ras_sys_fn = { .detect_ras_interrupt = amdgpu_ras_sys_detect_ras_interrupt, .get_gpu_mem = amdgpu_ras_sys_get_gpu_mem, .put_gpu_mem = amdgpu_ras_sys_put_gpu_mem, + .check_address_sanity = amdgpu_ras_sys_check_address_sanity, }; diff --git a/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h b/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h index f34dda7ce87b..2775c7bf41b7 100644 --- a/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h +++ b/drivers/gpu/drm/amd/ras/ras_mgr/ras_sys.h @@ -30,6 +30,9 @@ #include #include "amdgpu.h" +/* inject address is 52 bits */ +#define RAS_UMC_INJECT_ADDR_LIMIT (0x1ULL << 52) + #define RAS_DEV_ERR(device, fmt, ...) \ do { \ if (device) \ diff --git a/drivers/gpu/drm/amd/ras/rascore/ras.h b/drivers/gpu/drm/amd/ras/rascore/ras.h index c059fcebaf00..878dfdfcb18a 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras.h +++ b/drivers/gpu/drm/amd/ras/rascore/ras.h @@ -167,6 +167,7 @@ struct ras_mp1_sys_func { enum ras_fw_eeprom_cmd index, uint32_t param, uint32_t *read_arg); int (*mp1_get_ras_enabled_mask)(struct ras_core_context *ras_core, uint64_t *enabled_mask); + int (*mp1_set_debug_mode)(struct ras_core_context *ras_core, bool enable); }; struct ras_eeprom_sys_func { @@ -231,6 +232,7 @@ struct ras_sys_func { enum gpu_mem_type mem_type, struct gpu_mem_block *gpu_mem); int (*put_gpu_mem)(struct ras_core_context *ras_core, enum gpu_mem_type mem_type, struct gpu_mem_block *gpu_mem); + int (*check_address_sanity)(struct ras_core_context *ras_core, uint64_t addr); }; struct ras_ecc_count { @@ -398,4 +400,7 @@ int ras_core_get_device_system_info(struct ras_core_context *ras_core, struct device_system_info *dev_info); int ras_core_convert_soc_pa_to_cur_nps_pages(struct ras_core_context *ras_core, uint64_t soc_pa, uint64_t *page_pfn, uint32_t max_pages); +int ras_core_check_address_sanity(struct ras_core_context *ras_core, uint64_t addr); + +int ras_core_set_debug_mode(struct ras_core_context *ras_core, bool enable); #endif diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c b/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c index 210fbd8851a6..840610538c1f 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_aca_v1_0.c @@ -213,7 +213,7 @@ static int aca_parse_umc_bank(struct ras_core_context *ras_core, struct aca_bank_reg *bank = (struct aca_bank_reg *)data; struct aca_bank_ecc *ecc = (struct aca_bank_ecc *)buf; struct aca_ecc_info bank_info; - uint32_t ext_error_code; + uint32_t ext_error_code, misc0_errcnt; uint64_t status0; status0 = bank->regs[ACA_REG_IDX__STATUS]; @@ -228,15 +228,14 @@ static int aca_parse_umc_bank(struct ras_core_context *ras_core, ecc->bank_info.addr = bank->regs[ACA_REG_IDX__ADDR]; ext_error_code = ACA_REG_STATUS_ERRORCODEEXT(status0); + misc0_errcnt = ACA_REG_MISC0_ERRCNT(bank->regs[ACA_REG_IDX__MISC0]); if (aca_check_umc_de(ras_core, status0)) - ecc->de_count = 1; + ecc->de_count = misc0_errcnt ? misc0_errcnt : 1; else if (aca_check_umc_ue(ras_core, status0)) - ecc->ue_count = ext_error_code ? - 1 : ACA_REG_MISC0_ERRCNT(bank->regs[ACA_REG_IDX__MISC0]); + ecc->ue_count = ext_error_code ? 1 : misc0_errcnt; else if (aca_check_umc_ce(ras_core, status0)) - ecc->ce_count = ext_error_code ? - 1 : ACA_REG_MISC0_ERRCNT(bank->regs[ACA_REG_IDX__MISC0]); + ecc->ce_count = ext_error_code ? 1 : misc0_errcnt; return 0; } @@ -266,7 +265,7 @@ static int aca_parse_bank_default(struct ras_core_context *ras_core, ecc->bank_info.addr = bank->regs[ACA_REG_IDX__ADDR]; if (aca_check_bank_is_de(ras_core, status)) { - ecc->de_count = 1; + ecc->de_count = 0; } else { if (bank->ecc_type == RAS_ERR_TYPE__UE) ecc->ue_count = 1; diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_core.c b/drivers/gpu/drm/amd/ras/rascore/ras_core.c index 62d124a3eeac..c63a358b7e57 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_core.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_core.c @@ -151,6 +151,11 @@ bool ras_core_gpu_is_rma(struct ras_core_context *ras_core) return ras_core->is_rma; } +int ras_core_set_debug_mode(struct ras_core_context *ras_core, bool enable) +{ + return ras_mp1_set_debug_mode(ras_core, enable); +} + static int ras_core_seqno_fifo_write(struct ras_core_context *ras_core, enum ras_seqno_fifo fifo_type, uint64_t seqno) { @@ -676,3 +681,13 @@ int ras_core_convert_soc_pa_to_cur_nps_pages(struct ras_core_context *ras_core, return count; } + +int ras_core_check_address_sanity(struct ras_core_context *ras_core, + uint64_t addr) +{ + if (ras_core && ras_core->sys_fn && + ras_core->sys_fn->check_address_sanity) + return ras_core->sys_fn->check_address_sanity(ras_core, addr); + + return 0; +} diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_eeprom.c b/drivers/gpu/drm/amd/ras/rascore/ras_eeprom.c index 3a0ea036c9be..62d1a319c08c 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_eeprom.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_eeprom.c @@ -746,6 +746,9 @@ static int ras_eeprom_update_header(struct ras_eeprom_control *control) int res; bad_page_count = ras_umc_get_badpage_count(ras_core); + ras_core_event_notify(ras_core, RAS_EVENT_ID__UPDATE_BAD_PAGE_NUM, + &bad_page_count); + /* Modify the header if it exceeds. */ if (threshold_config != 0 && diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_eeprom_fw.c b/drivers/gpu/drm/amd/ras/rascore/ras_eeprom_fw.c index f5fa80db91fb..59e195652e42 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_eeprom_fw.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_eeprom_fw.c @@ -72,7 +72,7 @@ int ras_fw_get_badpage_count(struct ras_core_context *ras_core, if (ret != -EBUSY) return ret; - mdelay(10); + usleep_range(10000, 15000); now = (uint64_t)ktime_to_ms(ktime_get()); } while (now < end); diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_mp1.c b/drivers/gpu/drm/amd/ras/rascore/ras_mp1.c index f3321df85021..26af09f3574a 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_mp1.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_mp1.c @@ -59,9 +59,20 @@ int ras_mp1_dump_bank(struct ras_core_context *ras_core, return mp1->ip_func->dump_valid_bank(ras_core, type, idx, reg_idx, val); } +int ras_mp1_set_debug_mode(struct ras_core_context *ras_core, bool enable) +{ + struct ras_mp1 *mp1 = &ras_core->ras_mp1; + + if (!mp1->ip_func || !mp1->ip_func->set_debug_mode) + return -EOPNOTSUPP; + + return mp1->ip_func->set_debug_mode(ras_core, enable); +} + int ras_mp1_hw_init(struct ras_core_context *ras_core) { struct ras_mp1 *mp1 = &ras_core->ras_mp1; + int ret = 0; mp1->mp1_ip_version = ras_core->config->mp1_ip_version; mp1->sys_func = ras_core->config->mp1_cfg.mp1_sys_fn; @@ -71,8 +82,14 @@ int ras_mp1_hw_init(struct ras_core_context *ras_core) } mp1->ip_func = ras_mp1_get_ip_funcs(ras_core, mp1->mp1_ip_version); + if (!mp1->ip_func) + return -EINVAL; - return mp1->ip_func ? RAS_CORE_OK : -EINVAL; + ret = ras_mp1_set_debug_mode(ras_core, false); + if (ret) + return -EINVAL; + + return ret; } int ras_mp1_hw_fini(struct ras_core_context *ras_core) diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_mp1.h b/drivers/gpu/drm/amd/ras/rascore/ras_mp1.h index de1d08286f41..5bc7c1b7fdab 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_mp1.h +++ b/drivers/gpu/drm/amd/ras/rascore/ras_mp1.h @@ -31,6 +31,7 @@ struct ras_mp1_ip_func { enum ras_err_type type, u32 *count); int (*dump_valid_bank)(struct ras_core_context *ras_core, enum ras_err_type type, u32 idx, u32 reg_idx, u64 *val); + int (*set_debug_mode)(struct ras_core_context *ras_core, bool enable); }; struct ras_mp1 { @@ -47,4 +48,6 @@ int ras_mp1_get_bank_count(struct ras_core_context *ras_core, int ras_mp1_dump_bank(struct ras_core_context *ras_core, u32 ecc_type, u32 idx, u32 reg_idx, u64 *val); + +int ras_mp1_set_debug_mode(struct ras_core_context *ras_core, bool enable); #endif diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_mp1_v13_0.c b/drivers/gpu/drm/amd/ras/rascore/ras_mp1_v13_0.c index 310d39fc816b..1fcfc1995ad3 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_mp1_v13_0.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_mp1_v13_0.c @@ -99,7 +99,20 @@ static int mp1_v13_0_dump_bank(struct ras_core_context *ras_core, return sys_func->mp1_dump_valid_bank(ras_core, msg, idx, reg_idx, val); } +static int mp1_v13_0_set_debug_mode(struct ras_core_context *ras_core, bool enable) +{ + struct ras_mp1 *mp1 = &ras_core->ras_mp1; + const struct ras_mp1_sys_func *sys_func = mp1->sys_func; + + if (!sys_func || !sys_func->mp1_set_debug_mode) + return -RAS_CORE_NOT_SUPPORTED; + + return sys_func->mp1_set_debug_mode(ras_core, enable); +} + + const struct ras_mp1_ip_func mp1_ras_func_v13_0 = { .get_valid_bank_count = mp1_v13_0_get_bank_count, .dump_valid_bank = mp1_v13_0_dump_bank, + .set_debug_mode = mp1_v13_0_set_debug_mode, }; diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_process.c b/drivers/gpu/drm/amd/ras/rascore/ras_process.c index 3267dcdb169c..c001074c8c56 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_process.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_process.c @@ -248,9 +248,10 @@ int ras_process_init(struct ras_core_context *ras_core) ras_proc->ras_process_thread = kthread_run(ras_process_thread, (void *)ras_core, "ras_process_thread"); - if (!ras_proc->ras_process_thread) { + if (IS_ERR(ras_proc->ras_process_thread)) { RAS_DEV_ERR(ras_core->dev, "Failed to create ras_process_thread.\n"); - ret = -ENOMEM; + ret = PTR_ERR(ras_proc->ras_process_thread); + ras_proc->ras_process_thread = NULL; goto err; } diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c index f32ee2fecf53..e366fb97293e 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_umc.c +++ b/drivers/gpu/drm/amd/ras/rascore/ras_umc.c @@ -406,7 +406,7 @@ static int ras_umc_update_eeprom_ram_data(struct ras_core_context *ras_core, struct ras_umc *ras_umc = &ras_core->ras_umc; struct eeprom_store_record *data = &ras_umc->umc_err_data.ram_data; uint64_t page_pfn[16]; - int count = 0, j; + int count = 0, i, j; if (!data->space_left && ras_umc_realloc_err_data_space(ras_core, data, 256)) { @@ -418,10 +418,23 @@ static int ras_umc_update_eeprom_ram_data(struct ras_core_context *ras_core, bps, bps->cur_nps, page_pfn, ARRAY_SIZE(page_pfn)); if (count > 0) { for (j = 0; j < count; j++) { + if (ras_core_check_address_sanity(ras_core, + page_pfn[j] << AMDGPU_GPU_PAGE_SHIFT)) { + + for (i = 0; i < data->count; i++) + if (page_pfn[j] == data->bps[i].cur_nps_retired_row_pfn) + break; + data->bps[data->count].cur_nps_retired_row_pfn = U64_MAX; + data->count++; + data->space_left--; + continue; + } + bps->cur_nps_retired_row_pfn = page_pfn[j]; memcpy(&data->bps[data->count], bps, sizeof(*data->bps)); data->count++; data->space_left--; + data->bad_page_num++; } } else { RAS_DEV_ERR(ras_core->dev, "Failed to convert record to nps pages!"); @@ -431,6 +444,14 @@ static int ras_umc_update_eeprom_ram_data(struct ras_core_context *ras_core, return 0; } +static void ras_umc_update_bad_pages(struct ras_core_context *ras_core) +{ + struct ras_umc *ras_umc = &ras_core->ras_umc; + struct eeprom_store_record *data = &ras_umc->umc_err_data.ram_data; + + data->bad_page_num_old = data->bad_page_num; +} + /* it deal with vram only. */ static int ras_umc_add_bad_pages(struct ras_core_context *ras_core, struct eeprom_umc_record *bps, @@ -506,6 +527,7 @@ int ras_umc_load_bad_pages(struct ras_core_context *ras_core) } else { ras_core->ras_umc.umc_err_data.last_retired_pfn = UMC_INV_MEM_PFN; ret = ras_umc_add_bad_pages(ras_core, bps, ras_num_recs, true); + ras_umc_update_bad_pages(ras_core); } kfree(bps); @@ -521,7 +543,8 @@ static int ras_umc_save_bad_pages(struct ras_core_context *ras_core) { struct ras_umc *ras_umc = &ras_core->ras_umc; struct eeprom_store_record *data = &ras_umc->umc_err_data.rom_data; - uint32_t eeprom_record_num; + struct eeprom_store_record *ram_data = &ras_umc->umc_err_data.ram_data; + uint32_t eeprom_record_num, logical_count = 0; int save_count; int ret = 0; @@ -534,6 +557,7 @@ static int ras_umc_save_bad_pages(struct ras_core_context *ras_core) eeprom_record_num = ras_eeprom_get_record_count(ras_core); mutex_lock(&ras_umc->umc_lock); save_count = data->count - eeprom_record_num; + logical_count = ram_data->bad_page_num - ram_data->bad_page_num_old; /* only new entries are saved */ if (save_count > 0) { if (ras_fw_eeprom_supported(ras_core)) @@ -547,8 +571,8 @@ static int ras_umc_save_bad_pages(struct ras_core_context *ras_core) ret = -EIO; goto exit; } - - RAS_DEV_INFO(ras_core->dev, "Saved %d pages to EEPROM table.\n", save_count); + ras_umc_update_bad_pages(ras_core); + RAS_DEV_INFO(ras_core->dev, "Saved %d pages to EEPROM table.\n", logical_count); } exit: diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_umc.h b/drivers/gpu/drm/amd/ras/rascore/ras_umc.h index 237525b46b9b..ee7100f25f51 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_umc.h +++ b/drivers/gpu/drm/amd/ras/rascore/ras_umc.h @@ -119,6 +119,12 @@ struct eeprom_store_record { int count; /* the space can place new entries */ int space_left; + /* logical bad page number */ + int bad_page_num; + /* the bad page number is ras_num_recs or + * ras_num_recs * retire_unit + */ + int bad_page_num_old; }; struct ras_umc_err_data { diff --git a/drivers/gpu/drm/amd/ras/rascore/ras_umc_v12_0.h b/drivers/gpu/drm/amd/ras/rascore/ras_umc_v12_0.h index 8a35ad856165..650b5f1f22f7 100644 --- a/drivers/gpu/drm/amd/ras/rascore/ras_umc_v12_0.h +++ b/drivers/gpu/drm/amd/ras/rascore/ras_umc_v12_0.h @@ -290,6 +290,8 @@ /* R13 bit shift should be considered, double the number */ #define UMC_V12_0_BAD_PAGE_NUM_PER_CHANNEL (UMC_V12_0_NA_MAP_PA_NUM * 2) +/* UMC register per channel offset */ +#define UMC_V12_0_PER_CHANNEL_OFFSET 0x400 /* C2, C3, C4, R13, four MCA bits are looped in page retirement */ #define UMC_V12_0_RETIRE_LOOP_BITS 4 diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c index 5ba62e637a61..9aad1d1d28ec 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_dev.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_dev.c @@ -313,7 +313,11 @@ void komeda_dev_destroy(struct komeda_dev *mdev) int komeda_dev_resume(struct komeda_dev *mdev) { - clk_prepare_enable(mdev->aclk); + int err; + + err = clk_prepare_enable(mdev->aclk); + if (err) + return err; mdev->funcs->enable_irq(mdev); diff --git a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c index 4bb5f250e95e..67fffab018ae 100644 --- a/drivers/gpu/drm/arm/display/komeda/komeda_drv.c +++ b/drivers/gpu/drm/arm/display/komeda/komeda_drv.c @@ -74,8 +74,11 @@ static int komeda_platform_probe(struct platform_device *pdev) } pm_runtime_enable(dev); - if (!pm_runtime_enabled(dev)) - komeda_dev_resume(mdrv->mdev); + if (!pm_runtime_enabled(dev)) { + err = komeda_dev_resume(mdrv->mdev); + if (err) + goto err_destroy_mdev; + } mdrv->kms = komeda_kms_attach(mdrv->mdev); if (IS_ERR(mdrv->kms)) { @@ -93,7 +96,7 @@ static int komeda_platform_probe(struct platform_device *pdev) pm_runtime_disable(dev); else komeda_dev_suspend(mdrv->mdev); - +err_destroy_mdev: komeda_dev_destroy(mdrv->mdev); free_mdrv: @@ -140,11 +143,12 @@ static int __maybe_unused komeda_pm_suspend(struct device *dev) static int __maybe_unused komeda_pm_resume(struct device *dev) { struct komeda_drv *mdrv = dev_get_drvdata(dev); + int err = 0; if (!pm_runtime_status_suspended(dev)) - komeda_dev_resume(mdrv->mdev); + err = komeda_dev_resume(mdrv->mdev); - return drm_mode_config_helper_resume(&mdrv->kms->base); + return err ? err : drm_mode_config_helper_resume(&mdrv->kms->base); } static const struct dev_pm_ops komeda_pm_ops = { diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c index 9abe800f598a..23fa942ae4bb 100644 --- a/drivers/gpu/drm/arm/malidp_drv.c +++ b/drivers/gpu/drm/arm/malidp_drv.c @@ -670,6 +670,11 @@ static int malidp_runtime_pm_suspend(struct device *dev) struct drm_device *drm = dev_get_drvdata(dev); struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; + struct clk_bulk_data clks[] = { + { .clk = hwdev->pclk }, + { .clk = hwdev->aclk }, + { .clk = hwdev->mclk }, + }; /* we can only suspend if the hardware is in config mode */ WARN_ON(!hwdev->hw->in_config_mode(hwdev)); @@ -677,9 +682,7 @@ static int malidp_runtime_pm_suspend(struct device *dev) malidp_se_irq_fini(hwdev); malidp_de_irq_fini(hwdev); hwdev->pm_suspended = true; - clk_disable_unprepare(hwdev->mclk); - clk_disable_unprepare(hwdev->aclk); - clk_disable_unprepare(hwdev->pclk); + clk_bulk_disable_unprepare(ARRAY_SIZE(clks), clks); return 0; } @@ -689,10 +692,17 @@ static int malidp_runtime_pm_resume(struct device *dev) struct drm_device *drm = dev_get_drvdata(dev); struct malidp_drm *malidp = drm_to_malidp(drm); struct malidp_hw_device *hwdev = malidp->dev; + struct clk_bulk_data clks[] = { + { .clk = hwdev->pclk }, + { .clk = hwdev->aclk }, + { .clk = hwdev->mclk }, + }; + int err; + + err = clk_bulk_prepare_enable(ARRAY_SIZE(clks), clks); + if (err) + return err; - clk_prepare_enable(hwdev->pclk); - clk_prepare_enable(hwdev->aclk); - clk_prepare_enable(hwdev->mclk); hwdev->pm_suspended = false; malidp_de_irq_hw_init(hwdev); malidp_se_irq_hw_init(hwdev); diff --git a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c index 46094cca2974..d4577663a1f0 100644 --- a/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c +++ b/drivers/gpu/drm/aspeed/aspeed_gfx_drv.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c index 8e8cfd66f23b..ea43f59f06b2 100644 --- a/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c +++ b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-tx.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/inno-hdmi.c b/drivers/gpu/drm/bridge/inno-hdmi.c index 1e2a039cf9e8..dd35f5a875d3 100644 --- a/drivers/gpu/drm/bridge/inno-hdmi.c +++ b/drivers/gpu/drm/bridge/inno-hdmi.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/ssd2825.c b/drivers/gpu/drm/bridge/ssd2825.c index e345f3a652c2..00a4ed4a0700 100644 --- a/drivers/gpu/drm/bridge/ssd2825.c +++ b/drivers/gpu/drm/bridge/ssd2825.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c index 4f9943b0223e..6124d3123f57 100644 --- a/drivers/gpu/drm/bridge/tc358762.c +++ b/drivers/gpu/drm/bridge/tc358762.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index 084e9d898e22..12b43245bb8f 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/bridge/th1520-dw-hdmi.c b/drivers/gpu/drm/bridge/th1520-dw-hdmi.c index 389eead5f1c4..cbea8b14cd4b 100644 --- a/drivers/gpu/drm/bridge/th1520-dw-hdmi.c +++ b/drivers/gpu/drm/bridge/th1520-dw-hdmi.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 4de36fda0544..7ce9e212770a 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3740,8 +3740,10 @@ void drm_dp_mst_topology_queue_probe(struct drm_dp_mst_topology_mgr *mgr) { mutex_lock(&mgr->lock); - if (drm_WARN_ON(mgr->dev, !mgr->mst_state || !mgr->mst_primary)) + if (!mgr->mst_state || !mgr->mst_primary) { + drm_dbg_kms(mgr->dev, "queue_probe skipped: topology torn down\n"); goto out_unlock; + } drm_dp_mst_topology_mgr_invalidate_mstb(mgr->mst_primary); drm_dp_mst_queue_probe_work(mgr); diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index 3f8e025fd6d9..e1eed13a8e94 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1469,6 +1469,25 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, } EXPORT_SYMBOL(drm_mode_duplicate); +static bool drm_mode_match_timings_vrr(const struct drm_display_mode *mode1, + const struct drm_display_mode *mode2) +{ + int mode1_vsync_start_offset = mode1->vtotal - mode1->vsync_start; + int mode1_vsync_end_offset = mode1->vtotal - mode1->vsync_end; + int mode2_vsync_start_offset = mode2->vtotal - mode2->vsync_start; + int mode2_vsync_end_offset = mode2->vtotal - mode2->vsync_end; + + return mode1->hdisplay == mode2->hdisplay && + mode1->hsync_start == mode2->hsync_start && + mode1->hsync_end == mode2->hsync_end && + mode1->htotal == mode2->htotal && + mode1->hskew == mode2->hskew && + mode1->vdisplay == mode2->vdisplay && + mode1_vsync_start_offset == mode2_vsync_start_offset && + mode1_vsync_end_offset == mode2_vsync_end_offset && + mode1->vscan == mode2->vscan; +} + static bool drm_mode_match_timings(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) { @@ -1538,6 +1557,10 @@ bool drm_mode_match(const struct drm_display_mode *mode1, if (!mode1 || !mode2) return false; + if (match_flags & DRM_MODE_MATCH_TIMINGS_VRR && + !drm_mode_match_timings_vrr(mode1, mode2)) + return false; + if (match_flags & DRM_MODE_MATCH_TIMINGS && !drm_mode_match_timings(mode1, mode2)) return false; diff --git a/drivers/gpu/drm/drm_panel_backlight_quirks.c b/drivers/gpu/drm/drm_panel_backlight_quirks.c index 537dc6dd0534..f85cb293a3db 100644 --- a/drivers/gpu/drm/drm_panel_backlight_quirks.c +++ b/drivers/gpu/drm/drm_panel_backlight_quirks.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c index 552631c3554a..c314b3cb5e70 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index e6d516e1976d..d9637ddfcfc4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c index ab3cd309505a..15042365dec0 100644 --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 07802a7f4ce5..c4de717505d7 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -83,8 +83,7 @@ i915-y += \ i915_fb_pin.o \ i915_hdcp_gsc.o \ i915_initial_plane.o \ - i915_overlay.o \ - i915_panic.o + i915_overlay.o # "Graphics Technology" (aka we talk to the gpu) gt-y += \ @@ -167,6 +166,7 @@ gem-y += \ gem/i915_gem_object.o \ gem/i915_gem_object_frontbuffer.o \ gem/i915_gem_pages.o \ + gem/i915_gem_panic.o \ gem/i915_gem_phys.o \ gem/i915_gem_pm.o \ gem/i915_gem_region.o \ @@ -356,6 +356,7 @@ i915-y += \ display/intel_dp_aux.o \ display/intel_dp_aux_backlight.o \ display/intel_dp_hdcp.o \ + display/intel_dp_link_caps.o \ display/intel_dp_link_training.o \ display/intel_dp_mst.o \ display/intel_dp_test.o \ diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 5ff1cdf4581a..b867443ff227 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -1222,7 +1222,8 @@ static bool ilk_digital_port_connected(struct intel_encoder *encoder) return intel_de_read(display, DEISR) & bit; } -static int g4x_dp_compute_config(struct intel_encoder *encoder, +static int g4x_dp_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { @@ -1232,7 +1233,7 @@ static int g4x_dp_compute_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(display) && encoder->port != PORT_A) crtc_state->has_pch_encoder = true; - ret = intel_dp_compute_config(encoder, crtc_state, conn_state); + ret = intel_dp_compute_config(state, encoder, crtc_state, conn_state); if (ret) return ret; @@ -1252,10 +1253,13 @@ static void g4x_dp_suspend_complete(struct intel_encoder *encoder) static void intel_dp_encoder_destroy(struct drm_encoder *encoder) { + struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder)); + intel_dp_encoder_flush_work(encoder); drm_encoder_cleanup(encoder); - kfree(enc_to_dig_port(to_intel_encoder(encoder))); + intel_dp_link_cleanup(&dig_port->dp); + kfree(dig_port); } static void intel_dp_encoder_reset(struct drm_encoder *encoder) @@ -1350,6 +1354,9 @@ bool g4x_dp_init(struct intel_display *display, intel_encoder->audio_enable = g4x_dp_audio_enable; intel_encoder->audio_disable = g4x_dp_audio_disable; + if (intel_dp_link_init(&dig_port->dp) != 0) + goto err_dp_init; + if ((display->platform.ivybridge && port == PORT_A) || (HAS_PCH_CPT(display) && port != PORT_A)) { dig_port->dp.set_link_train = cpt_set_link_train; @@ -1419,6 +1426,8 @@ bool g4x_dp_init(struct intel_display *display, return true; err_init_connector: + intel_dp_link_cleanup(&dig_port->dp); +err_dp_init: drm_encoder_cleanup(encoder); err_encoder_init: kfree(intel_connector); diff --git a/drivers/gpu/drm/i915/display/g4x_hdmi.c b/drivers/gpu/drm/i915/display/g4x_hdmi.c index acb36cab999c..4c33aa1d1d32 100644 --- a/drivers/gpu/drm/i915/display/g4x_hdmi.c +++ b/drivers/gpu/drm/i915/display/g4x_hdmi.c @@ -126,12 +126,12 @@ static bool g4x_compute_has_hdmi_sink(struct intel_atomic_state *state, return false; } -static int g4x_hdmi_compute_config(struct intel_encoder *encoder, +static int g4x_hdmi_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { struct intel_display *display = to_intel_display(encoder); - struct intel_atomic_state *state = to_intel_atomic_state(crtc_state->uapi.state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); if (HAS_PCH_SPLIT(display)) diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index a549f1fac810..ea0cdb7822f3 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -1657,7 +1657,8 @@ static int gen11_dsi_dsc_compute_config(struct intel_encoder *encoder, return 0; } -static int gen11_dsi_compute_config(struct intel_encoder *encoder, +static int gen11_dsi_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { @@ -1671,7 +1672,7 @@ static int gen11_dsi_compute_config(struct intel_encoder *encoder, pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - ret = intel_panel_compute_config(intel_connector, adjusted_mode); + ret = intel_panel_compute_config(state, pipe_config, intel_connector); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_alpm.c b/drivers/gpu/drm/i915/display/intel_alpm.c index c6963ea420cc..f1383764b702 100644 --- a/drivers/gpu/drm/i915/display/intel_alpm.c +++ b/drivers/gpu/drm/i915/display/intel_alpm.c @@ -291,7 +291,9 @@ void intel_alpm_lobf_compute_config_late(struct intel_dp *intel_dp, if (!crtc_state->has_lobf) return; - if (!intel_alpm_lobf_is_window1_sufficient(crtc_state)) { + if (crtc_state->has_psr || + !intel_vrr_is_fixed_rr(crtc_state) || + !intel_alpm_lobf_is_window1_sufficient(crtc_state)) { crtc_state->has_lobf = false; return; } @@ -343,11 +345,7 @@ void intel_alpm_lobf_compute_config(struct intel_dp *intel_dp, if (!intel_dp->as_sdp_supported) return; - if (crtc_state->has_psr) - return; - - if (!intel_vrr_always_use_vrr_tg(display) || - !intel_vrr_is_fixed_rr(crtc_state)) + if (!intel_vrr_always_use_vrr_tg(display)) return; if (!(intel_alpm_aux_wake_supported(intel_dp) || @@ -407,6 +405,11 @@ static void lnl_alpm_configure(struct intel_dp *intel_dp, if (crtc_state->disable_as_sdp_when_pr_active) pr_alpm_ctl |= PR_ALPM_CTL_AS_SDP_TRANSMISSION_IN_ACTIVE_DISABLE; + if (intel_display_power_dc3co_allowed(display)) + pr_alpm_ctl |= PR_ALPM_CTL_USE_DC3CO_IDLE_PROTOCOL; + else + pr_alpm_ctl &= ~PR_ALPM_CTL_USE_DC3CO_IDLE_PROTOCOL; + intel_de_write(display, PR_ALPM_CTL(display, cpu_transcoder), pr_alpm_ctl); } diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index b6fe87c29aa7..97cbae2e547e 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -623,6 +623,21 @@ get_lfp_data_tail(const struct bdb_lfp_data *data, return NULL; } +static bool is_panel_type_valid(int panel_type) +{ + return panel_type >= 0 && panel_type < 16; +} + +static bool is_panel_type_pnp(int panel_type) +{ + return panel_type == 0xff; +} + +static bool is_panel_type_valid_or_pnp(int panel_type) +{ + return is_panel_type_valid(panel_type) || is_panel_type_pnp(panel_type); +} + static int opregion_get_panel_type(struct intel_display *display, const struct intel_bios_encoder_data *devdata, const struct drm_edid *drm_edid, bool use_fallback) @@ -640,15 +655,21 @@ static int vbt_get_panel_type(struct intel_display *display, if (!lfp_options) return -1; - if (lfp_options->panel_type > 0xf && - lfp_options->panel_type != 0xff) { + if (!is_panel_type_valid_or_pnp(lfp_options->panel_type)) { drm_dbg_kms(display->drm, "Invalid VBT panel type 0x%x\n", lfp_options->panel_type); return -1; } - if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2) + if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2) { + if (!is_panel_type_valid_or_pnp(lfp_options->panel_type2)) { + drm_dbg_kms(display->drm, "Invalid VBT panel type 2 0x%x\n", + lfp_options->panel_type2); + return -1; + } + return lfp_options->panel_type2; + } drm_WARN_ON(display->drm, devdata && devdata->child.handle != DEVICE_HANDLE_LFP1); @@ -762,13 +783,12 @@ static int get_panel_type(struct intel_display *display, panel_types[i].name, panel_types[i].panel_type); } - if (panel_types[PANEL_TYPE_OPREGION].panel_type >= 0) + if (is_panel_type_valid(panel_types[PANEL_TYPE_OPREGION].panel_type)) i = PANEL_TYPE_OPREGION; - else if (panel_types[PANEL_TYPE_VBT].panel_type == 0xff && - panel_types[PANEL_TYPE_PNPID].panel_type >= 0) + else if (is_panel_type_pnp(panel_types[PANEL_TYPE_VBT].panel_type) && + is_panel_type_valid(panel_types[PANEL_TYPE_PNPID].panel_type)) i = PANEL_TYPE_PNPID; - else if (panel_types[PANEL_TYPE_VBT].panel_type != 0xff && - panel_types[PANEL_TYPE_VBT].panel_type >= 0) + else if (is_panel_type_valid(panel_types[PANEL_TYPE_VBT].panel_type)) i = PANEL_TYPE_VBT; else i = PANEL_TYPE_FALLBACK; @@ -2197,52 +2217,52 @@ static u8 translate_iboost(struct intel_display *display, u8 val) static const u8 cnp_ddc_pin_map[] = { [0] = 0, /* N/A */ - [GMBUS_PIN_1_BXT] = DDC_BUS_DDI_B, - [GMBUS_PIN_2_BXT] = DDC_BUS_DDI_C, - [GMBUS_PIN_4_CNP] = DDC_BUS_DDI_D, /* sic */ - [GMBUS_PIN_3_BXT] = DDC_BUS_DDI_F, /* sic */ + [GMBUS_PIN_1] = DDC_BUS_DDI_B, + [GMBUS_PIN_2] = DDC_BUS_DDI_C, + [GMBUS_PIN_4] = DDC_BUS_DDI_D, /* sic */ + [GMBUS_PIN_3] = DDC_BUS_DDI_F, /* sic */ }; static const u8 icp_ddc_pin_map[] = { - [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A, - [GMBUS_PIN_2_BXT] = ICL_DDC_BUS_DDI_B, - [GMBUS_PIN_3_BXT] = TGL_DDC_BUS_DDI_C, - [GMBUS_PIN_9_TC1_ICP] = ICL_DDC_BUS_PORT_1, - [GMBUS_PIN_10_TC2_ICP] = ICL_DDC_BUS_PORT_2, - [GMBUS_PIN_11_TC3_ICP] = ICL_DDC_BUS_PORT_3, - [GMBUS_PIN_12_TC4_ICP] = ICL_DDC_BUS_PORT_4, - [GMBUS_PIN_13_TC5_TGP] = TGL_DDC_BUS_PORT_5, - [GMBUS_PIN_14_TC6_TGP] = TGL_DDC_BUS_PORT_6, + [GMBUS_PIN_1] = ICL_DDC_BUS_DDI_A, + [GMBUS_PIN_2] = ICL_DDC_BUS_DDI_B, + [GMBUS_PIN_3] = TGL_DDC_BUS_DDI_C, + [GMBUS_PIN_9_TC1] = ICL_DDC_BUS_PORT_1, + [GMBUS_PIN_10_TC2] = ICL_DDC_BUS_PORT_2, + [GMBUS_PIN_11_TC3] = ICL_DDC_BUS_PORT_3, + [GMBUS_PIN_12_TC4] = ICL_DDC_BUS_PORT_4, + [GMBUS_PIN_13_TC5] = TGL_DDC_BUS_PORT_5, + [GMBUS_PIN_14_TC6] = TGL_DDC_BUS_PORT_6, }; static const u8 rkl_pch_tgp_ddc_pin_map[] = { - [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A, - [GMBUS_PIN_2_BXT] = ICL_DDC_BUS_DDI_B, - [GMBUS_PIN_9_TC1_ICP] = RKL_DDC_BUS_DDI_D, - [GMBUS_PIN_10_TC2_ICP] = RKL_DDC_BUS_DDI_E, + [GMBUS_PIN_1] = ICL_DDC_BUS_DDI_A, + [GMBUS_PIN_2] = ICL_DDC_BUS_DDI_B, + [GMBUS_PIN_9_TC1] = RKL_DDC_BUS_DDI_D, + [GMBUS_PIN_10_TC2] = RKL_DDC_BUS_DDI_E, }; static const u8 adls_ddc_pin_map[] = { - [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A, - [GMBUS_PIN_9_TC1_ICP] = ADLS_DDC_BUS_PORT_TC1, - [GMBUS_PIN_10_TC2_ICP] = ADLS_DDC_BUS_PORT_TC2, - [GMBUS_PIN_11_TC3_ICP] = ADLS_DDC_BUS_PORT_TC3, - [GMBUS_PIN_12_TC4_ICP] = ADLS_DDC_BUS_PORT_TC4, + [GMBUS_PIN_1] = ICL_DDC_BUS_DDI_A, + [GMBUS_PIN_9_TC1] = ADLS_DDC_BUS_PORT_TC1, + [GMBUS_PIN_10_TC2] = ADLS_DDC_BUS_PORT_TC2, + [GMBUS_PIN_11_TC3] = ADLS_DDC_BUS_PORT_TC3, + [GMBUS_PIN_12_TC4] = ADLS_DDC_BUS_PORT_TC4, }; static const u8 gen9bc_tgp_ddc_pin_map[] = { - [GMBUS_PIN_2_BXT] = DDC_BUS_DDI_B, - [GMBUS_PIN_9_TC1_ICP] = DDC_BUS_DDI_C, - [GMBUS_PIN_10_TC2_ICP] = DDC_BUS_DDI_D, + [GMBUS_PIN_2] = DDC_BUS_DDI_B, + [GMBUS_PIN_9_TC1] = DDC_BUS_DDI_C, + [GMBUS_PIN_10_TC2] = DDC_BUS_DDI_D, }; static const u8 adlp_ddc_pin_map[] = { - [GMBUS_PIN_1_BXT] = ICL_DDC_BUS_DDI_A, - [GMBUS_PIN_2_BXT] = ICL_DDC_BUS_DDI_B, - [GMBUS_PIN_9_TC1_ICP] = ADLP_DDC_BUS_PORT_TC1, - [GMBUS_PIN_10_TC2_ICP] = ADLP_DDC_BUS_PORT_TC2, - [GMBUS_PIN_11_TC3_ICP] = ADLP_DDC_BUS_PORT_TC3, - [GMBUS_PIN_12_TC4_ICP] = ADLP_DDC_BUS_PORT_TC4, + [GMBUS_PIN_1] = ICL_DDC_BUS_DDI_A, + [GMBUS_PIN_2] = ICL_DDC_BUS_DDI_B, + [GMBUS_PIN_9_TC1] = ADLP_DDC_BUS_PORT_TC1, + [GMBUS_PIN_10_TC2] = ADLP_DDC_BUS_PORT_TC2, + [GMBUS_PIN_11_TC3] = ADLP_DDC_BUS_PORT_TC3, + [GMBUS_PIN_12_TC4] = ADLP_DDC_BUS_PORT_TC4, }; static u8 map_ddc_pin(struct intel_display *display, u8 vbt_pin) diff --git a/drivers/gpu/drm/i915/display/intel_bw.c b/drivers/gpu/drm/i915/display/intel_bw.c index dc5a5b639d87..41539fdfeac5 100644 --- a/drivers/gpu/drm/i915/display/intel_bw.c +++ b/drivers/gpu/drm/i915/display/intel_bw.c @@ -59,7 +59,7 @@ struct intel_psf_gv_point { struct intel_qgv_info { struct intel_qgv_point points[I915_NUM_QGV_POINTS]; struct intel_psf_gv_point psf_points[I915_NUM_PSF_GV_POINTS]; - u8 num_points; + u8 num_qgv_points; u8 num_psf_points; u8 t_bl; u8 max_numchannels; @@ -155,8 +155,8 @@ static int adls_pcode_read_psf_gv_point_info(struct intel_display *display, static u16 icl_qgv_points_mask(struct intel_display *display) { - unsigned int num_psf_gv_points = display->bw.max[0].num_psf_gv_points; - unsigned int num_qgv_points = display->bw.max[0].num_qgv_points; + unsigned int num_psf_gv_points = display->bw.num_psf_gv_points; + unsigned int num_qgv_points = display->bw.num_qgv_points; u16 qgv_points = 0, psf_points = 0; /* @@ -252,7 +252,7 @@ static int icl_get_qgv_points(struct intel_display *display, { int i, ret; - qi->num_points = dram_info->num_qgv_points; + qi->num_qgv_points = dram_info->num_qgv_points; qi->num_psf_points = dram_info->num_psf_gv_points; if (DISPLAY_VER(display) >= 14) { @@ -324,10 +324,10 @@ static int icl_get_qgv_points(struct intel_display *display, } if (drm_WARN_ON(display->drm, - qi->num_points > ARRAY_SIZE(qi->points))) - qi->num_points = ARRAY_SIZE(qi->points); + qi->num_qgv_points > ARRAY_SIZE(qi->points))) + qi->num_qgv_points = ARRAY_SIZE(qi->points); - for (i = 0; i < qi->num_points; i++) { + for (i = 0; i < qi->num_qgv_points; i++) { struct intel_qgv_point *sp = &qi->points[i]; ret = intel_read_qgv_point_info(display, sp, i); @@ -373,7 +373,7 @@ static int icl_sagv_max_dclk(const struct intel_qgv_info *qi) u16 dclk = 0; int i; - for (i = 0; i < qi->num_points; i++) + for (i = 0; i < qi->num_qgv_points; i++) dclk = max(dclk, qi->points[i].dclk); return dclk; @@ -536,6 +536,9 @@ static int icl_get_bw_info(struct intel_display *display, ipqdepth = min(ipqdepthpch, display_bw_params->displayrtids / num_channels); qi.deinterleave = DIV_ROUND_UP(num_channels, is_y_tile(display) ? 4 : 2); + display->bw.num_qgv_points = qi.num_qgv_points; + display->bw.num_psf_gv_points = qi.num_psf_points; + for (i = 0; i < num_groups; i++) { struct intel_bw_info *bi = &display->bw.max[i]; int clpchgroup; @@ -544,10 +547,7 @@ static int icl_get_bw_info(struct intel_display *display, clpchgroup = (display_bw_params->deburst * qi.deinterleave / num_channels) << i; bi->num_planes = (ipqdepth - clpchgroup) / clpchgroup + 1; - bi->num_qgv_points = qi.num_points; - bi->num_psf_gv_points = qi.num_psf_points; - - for (j = 0; j < qi.num_points; j++) { + for (j = 0; j < qi.num_qgv_points; j++) { const struct intel_qgv_point *sp = &qi.points[j]; int ct, bw; @@ -574,7 +574,7 @@ static int icl_get_bw_info(struct intel_display *display, * SAGV point, but we can't send PCode commands to restrict it * as it will fail and pointless anyway. */ - if (qi.num_points == 1) + if (qi.num_qgv_points == 1) display->sagv.status = I915_SAGV_NOT_CONTROLLED; else display->sagv.status = I915_SAGV_ENABLED; @@ -629,16 +629,20 @@ static int tgl_get_bw_info(struct intel_display *display, */ clperchgroup = 4 * (8 / num_channels) * qi.deinterleave; + display->bw.num_qgv_points = qi.num_qgv_points; + display->bw.num_psf_gv_points = qi.num_psf_points; + + display->bw.max[0].num_planes = U8_MAX; + for (i = 0; i < num_groups; i++) { struct intel_bw_info *bi = &display->bw.max[i]; - struct intel_bw_info *bi_next; int clpchgroup; int j; clpchgroup = (display_bw_params->deburst * qi.deinterleave / num_channels) << i; if (i < num_groups - 1) { - bi_next = &display->bw.max[i + 1]; + struct intel_bw_info *bi_next = &display->bw.max[i + 1]; if (clpchgroup < clperchgroup) bi_next->num_planes = (ipqdepth - clpchgroup) / clpchgroup; @@ -646,10 +650,7 @@ static int tgl_get_bw_info(struct intel_display *display, bi_next->num_planes = 0; } - bi->num_qgv_points = qi.num_points; - bi->num_psf_gv_points = qi.num_psf_points; - - for (j = 0; j < qi.num_points; j++) { + for (j = 0; j < qi.num_qgv_points; j++) { const struct intel_qgv_point *sp = &qi.points[j]; int ct, bw; @@ -665,23 +666,27 @@ static int tgl_get_bw_info(struct intel_display *display, bi->deratedbw[j] = min(maxdebw, bw * (100 - soc_bw_params->derating) / 100); - bi->peakbw[j] = tgl_peakbw(num_channels, qi.channel_width, sp->dclk); drm_dbg_kms(display->drm, - "BW%d / QGV %d: num_planes=%d deratedbw=%u peakbw: %u\n", - i, j, bi->num_planes, bi->deratedbw[j], - bi->peakbw[j]); + "BW%d / QGV %d: num_planes=%d deratedbw=%u\n", + i, j, bi->num_planes, bi->deratedbw[j]); } + } - for (j = 0; j < qi.num_psf_points; j++) { - const struct intel_psf_gv_point *sp = &qi.psf_points[j]; + for (i = 0; i < qi.num_qgv_points; i++) { + const struct intel_qgv_point *sp = &qi.points[i]; - bi->psf_bw[j] = adl_calc_psf_bw(sp->clk); + display->bw.peakbw[i] = tgl_peakbw(num_channels, qi.channel_width, sp->dclk); - drm_dbg_kms(display->drm, - "BW%d / PSF GV %d: num_planes=%d bw=%u\n", - i, j, bi->num_planes, bi->psf_bw[j]); - } + drm_dbg_kms(display->drm, "QGV %d: peakbw=%u\n", i, display->bw.peakbw[i]); + } + + for (i = 0; i < qi.num_psf_points; i++) { + const struct intel_psf_gv_point *sp = &qi.psf_points[i]; + + display->bw.psf_bw[i] = adl_calc_psf_bw(sp->clk); + + drm_dbg_kms(display->drm, "PSF GV %d: bw=%u\n", i, display->bw.psf_bw[i]); } /* @@ -689,7 +694,7 @@ static int tgl_get_bw_info(struct intel_display *display, * SAGV point, but we can't send PCode commands to restrict it * as it will fail and pointless anyway. */ - if (qi.num_points == 1) + if (qi.num_qgv_points == 1) display->sagv.status = I915_SAGV_NOT_CONTROLLED; else display->sagv.status = I915_SAGV_ENABLED; @@ -699,25 +704,20 @@ static int tgl_get_bw_info(struct intel_display *display, static void dg2_get_bw_info(struct intel_display *display) { - unsigned int deratedbw = display->platform.dg2_g11 ? 38000 : 50000; - int num_groups = ARRAY_SIZE(display->bw.max); int i; - /* - * DG2 doesn't have SAGV or QGV points, just a constant max bandwidth - * that doesn't depend on the number of planes enabled. So fill all the - * plane group with constant bw information for uniformity with other - * platforms. DG2-G10 platforms have a constant 50 GB/s bandwidth, - * whereas DG2-G11 platforms have 38 GB/s. - */ - for (i = 0; i < num_groups; i++) { - struct intel_bw_info *bi = &display->bw.max[i]; + display->bw.num_qgv_points = 1; - bi->num_planes = 1; - /* Need only one dummy QGV point per group */ - bi->num_qgv_points = 1; - bi->deratedbw[0] = deratedbw; - } + display->bw.max[0].num_planes = U8_MAX; + display->bw.max[0].deratedbw[0] = display->platform.dg2_g11 ? 38000 : 50000; + + drm_dbg_kms(display->drm, + "QGV 0: deratedbw=%u\n", + display->bw.max[0].deratedbw[0]); + + /* Bandwidth does not depend on # of planes; set all groups the same */ + for (i = 1; i < ARRAY_SIZE(display->bw.max); i++) + display->bw.max[i] = display->bw.max[0]; display->sagv.status = I915_SAGV_NOT_CONTROLLED; } @@ -741,31 +741,32 @@ static int xe2_hpd_get_bw_info(struct intel_display *display, peakbw = tgl_peakbw(num_channels, qi.channel_width, icl_sagv_max_dclk(&qi)); maxdebw = min(soc_bw_params->deprogbwlimit * 1000, peakbw * DEPROGBWPCLIMIT / 100); - for (i = 0; i < qi.num_points; i++) { + display->bw.num_qgv_points = qi.num_qgv_points; + + display->bw.max[0].num_planes = U8_MAX; + + for (i = 0; i < qi.num_qgv_points; i++) { const struct intel_qgv_point *sp = &qi.points[i]; int bw = tgl_peakbw(num_channels, qi.channel_width, sp->dclk); display->bw.max[0].deratedbw[i] = min(maxdebw, (100 - soc_bw_params->derating) * bw / 100); - display->bw.max[0].peakbw[i] = bw; - drm_dbg_kms(display->drm, "QGV %d: deratedbw=%u peakbw: %u\n", - i, display->bw.max[0].deratedbw[i], - display->bw.max[0].peakbw[i]); + display->bw.peakbw[i] = bw; + + drm_dbg_kms(display->drm, "QGV %d: deratedbw=%u peakbw=%u\n", + i, display->bw.max[0].deratedbw[i], display->bw.peakbw[i]); } /* Bandwidth does not depend on # of planes; set all groups the same */ - display->bw.max[0].num_planes = 1; - display->bw.max[0].num_qgv_points = qi.num_points; for (i = 1; i < ARRAY_SIZE(display->bw.max); i++) - memcpy(&display->bw.max[i], &display->bw.max[0], - sizeof(display->bw.max[0])); + display->bw.max[i] = display->bw.max[0]; /* * Xe2_HPD should always have exactly two QGV points representing * battery and plugged-in operation. */ - drm_WARN_ON(display->drm, qi.num_points != 2); + drm_WARN_ON(display->drm, qi.num_qgv_points != 2); display->sagv.status = I915_SAGV_ENABLED; return 0; @@ -776,6 +777,9 @@ static unsigned int icl_max_bw_index(struct intel_display *display, { int i; + if (qgv_point >= display->bw.num_qgv_points) + return UINT_MAX; + /* * Let's return max bw for 0 planes */ @@ -785,13 +789,6 @@ static unsigned int icl_max_bw_index(struct intel_display *display, const struct intel_bw_info *bi = &display->bw.max[i]; - /* - * Pcode will not expose all QGV points when - * SAGV is forced to off/min/med/max. - */ - if (qgv_point >= bi->num_qgv_points) - return UINT_MAX; - if (num_planes >= bi->num_planes) return i; } @@ -804,31 +801,24 @@ static unsigned int tgl_max_bw_index(struct intel_display *display, { int i; + if (qgv_point >= display->bw.num_qgv_points) + return UINT_MAX; + for (i = ARRAY_SIZE(display->bw.max) - 1; i >= 0; i--) { const struct intel_bw_info *bi = &display->bw.max[i]; - /* - * Pcode will not expose all QGV points when - * SAGV is forced to off/min/med/max. - */ - if (qgv_point >= bi->num_qgv_points) - return UINT_MAX; - if (num_planes <= bi->num_planes) return i; } - return 0; + return UINT_MAX; } static unsigned int adl_psf_bw(struct intel_display *display, int psf_gv_point) { - const struct intel_bw_info *bi = - &display->bw.max[0]; - - return bi->psf_bw[psf_gv_point]; + return display->bw.psf_bw[psf_gv_point]; } static unsigned int icl_qgv_bw(struct intel_display *display, @@ -950,7 +940,7 @@ intel_atomic_get_bw_state(struct intel_atomic_state *state) static unsigned int icl_max_bw_qgv_point_mask(struct intel_display *display, int num_active_planes) { - unsigned int num_qgv_points = display->bw.max[0].num_qgv_points; + unsigned int num_qgv_points = display->bw.num_qgv_points; unsigned int max_bw_point = 0; unsigned int max_bw = 0; int i; @@ -986,7 +976,7 @@ static u16 icl_prepare_qgv_points_mask(struct intel_display *display, static unsigned int icl_max_bw_psf_gv_point_mask(struct intel_display *display) { - unsigned int num_psf_gv_points = display->bw.max[0].num_psf_gv_points; + unsigned int num_psf_gv_points = display->bw.num_psf_gv_points; unsigned int max_bw_point_mask = 0; unsigned int max_bw = 0; int i; @@ -1091,7 +1081,7 @@ static int mtl_find_qgv_points(struct intel_display *display, struct intel_bw_state *new_bw_state) { unsigned int best_rate = UINT_MAX; - unsigned int num_qgv_points = display->bw.max[0].num_qgv_points; + unsigned int num_qgv_points = display->bw.num_qgv_points; unsigned int qgv_peak_bw = 0; int i; int ret; @@ -1116,21 +1106,15 @@ static int mtl_find_qgv_points(struct intel_display *display, * offered per plane group */ for (i = 0; i < num_qgv_points; i++) { - unsigned int bw_index = - tgl_max_bw_index(display, num_active_planes, i); - unsigned int max_data_rate; - - if (bw_index >= ARRAY_SIZE(display->bw.max)) - continue; - - max_data_rate = display->bw.max[bw_index].deratedbw[i]; + unsigned int max_data_rate = + icl_qgv_bw(display, num_active_planes, i); if (max_data_rate < data_rate) continue; - if (max_data_rate - data_rate < best_rate) { - best_rate = max_data_rate - data_rate; - qgv_peak_bw = display->bw.max[bw_index].peakbw[i]; + if (max_data_rate < best_rate) { + best_rate = max_data_rate; + qgv_peak_bw = display->bw.peakbw[i]; } drm_dbg_kms(display->drm, "QGV point %d: max bw %d required %d qgv_peak_bw: %d\n", @@ -1162,8 +1146,8 @@ static int icl_find_qgv_points(struct intel_display *display, const struct intel_bw_state *old_bw_state, struct intel_bw_state *new_bw_state) { - unsigned int num_psf_gv_points = display->bw.max[0].num_psf_gv_points; - unsigned int num_qgv_points = display->bw.max[0].num_qgv_points; + unsigned int num_psf_gv_points = display->bw.num_psf_gv_points; + unsigned int num_qgv_points = display->bw.num_qgv_points; u16 psf_points = 0; u16 qgv_points = 0; int i; diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index 7bc9b956554b..d3c5e3438d19 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -1229,23 +1229,28 @@ static void skl_set_cdclk(struct intel_display *display, static void skl_sanitize_cdclk(struct intel_display *display) { - u32 cdctl, expected; + u32 cdctl, expected, swf18; /* * check if the pre-os initialized the display * There is SWF18 scratchpad register defined which is set by the * pre-os which can be used by the OS drivers to check the status */ - if ((intel_de_read(display, SWF_ILK(0x18)) & 0x00FFFFFF) == 0) + swf18 = intel_de_read(display, SWF_ILK(0x18)); + if ((swf18 & 0x00FFFFFF) == 0) { + drm_dbg_kms(display->drm, "Sanitizing CDCLK due to SWF18 0x%x\n", swf18); goto sanitize; + } intel_update_cdclk(display); intel_cdclk_dump_config(display, &display->cdclk.hw, "Current CDCLK"); /* Is PLL enabled and locked ? */ if (display->cdclk.hw.vco == 0 || - display->cdclk.hw.cdclk == display->cdclk.hw.bypass) + display->cdclk.hw.cdclk == display->cdclk.hw.bypass) { + drm_dbg_kms(display->drm, "Sanitizing CDCLK due to PLL not enabled/locked\n"); goto sanitize; + } /* DPLL okay; verify the cdclock * @@ -1261,8 +1266,11 @@ static void skl_sanitize_cdclk(struct intel_display *display) cdctl &= ~CDCLK_FREQ_DECIMAL_MASK; cdctl |= expected & CDCLK_FREQ_DECIMAL_MASK; - if (cdctl != expected) + if (cdctl != expected) { + drm_dbg_kms(display->drm, "Sanitizing CDCLK due to CDCLK_CTL 0x%x, expected 0x%x)\n", + intel_de_read(display, CDCLK_CTL), expected); goto sanitize; + } drm_dbg_kms(display->drm, "Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n", intel_de_read(display, CDCLK_CTL), expected); @@ -1274,8 +1282,6 @@ static void skl_sanitize_cdclk(struct intel_display *display) return; sanitize: - drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n"); - /* force cdclk programming */ display->cdclk.hw.cdclk = 0; /* force full PLL disable + enable */ @@ -1938,14 +1944,17 @@ static void adlp_cdclk_pll_crawl(struct intel_display *display, int vco) display->cdclk.hw.vco = vco; } +static u32 bxt_cdclk_cd2x_pipe_mask(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 11) + return ICL_CDCLK_CD2X_PIPE_MASK; + else + return BXT_CDCLK_CD2X_PIPE_MASK; +} + static u32 bxt_cdclk_cd2x_pipe(struct intel_display *display, enum pipe pipe) { - if (DISPLAY_VER(display) >= 12) { - if (pipe == INVALID_PIPE) - return TGL_CDCLK_CD2X_PIPE_NONE; - else - return TGL_CDCLK_CD2X_PIPE(pipe); - } else if (DISPLAY_VER(display) >= 11) { + if (DISPLAY_VER(display) >= 11) { if (pipe == INVALID_PIPE) return ICL_CDCLK_CD2X_PIPE_NONE; else @@ -2340,18 +2349,24 @@ static void bxt_sanitize_cdclk(struct intel_display *display) intel_cdclk_dump_config(display, &display->cdclk.hw, "Current CDCLK"); if (display->cdclk.hw.vco == 0 || - display->cdclk.hw.cdclk == display->cdclk.hw.bypass) + display->cdclk.hw.cdclk == display->cdclk.hw.bypass) { + drm_dbg_kms(display->drm, "Sanitizing CDCLK due to PLL not enabled/locked\n"); goto sanitize; + } /* Make sure this is a legal cdclk value for the platform */ cdclk = bxt_calc_cdclk(display, display->cdclk.hw.cdclk); - if (cdclk != display->cdclk.hw.cdclk) + if (cdclk != display->cdclk.hw.cdclk) { + drm_dbg_kms(display->drm, "Sanitizing CDCLK due to bad CDCLK frequency\n"); goto sanitize; + } /* Make sure the VCO is correct for the cdclk */ vco = bxt_calc_cdclk_pll_vco(display, cdclk); - if (vco != display->cdclk.hw.vco) + if (vco != display->cdclk.hw.vco) { + drm_dbg_kms(display->drm, "Sanitizing CDCLK due to bad VCO frequency\n"); goto sanitize; + } /* * Some BIOS versions leave an incorrect decimal frequency value and @@ -2366,7 +2381,7 @@ static void bxt_sanitize_cdclk(struct intel_display *display) * dividers both syncing to an active pipe, or asynchronously * (PIPE_NONE). */ - cdctl &= ~bxt_cdclk_cd2x_pipe(display, INVALID_PIPE); + cdctl &= ~bxt_cdclk_cd2x_pipe_mask(display); cdctl |= bxt_cdclk_cd2x_pipe(display, INVALID_PIPE); if (cdctl != expected) { @@ -2375,8 +2390,11 @@ static void bxt_sanitize_cdclk(struct intel_display *display) cdctl |= expected & CDCLK_FREQ_DECIMAL_MASK; } - if (cdctl != expected) + if (cdctl != expected) { + drm_dbg_kms(display->drm, "Sanitizing CDCLK due to CDCLK_CTL 0x%x, expected 0x%x\n", + intel_de_read(display, CDCLK_CTL), expected); goto sanitize; + } drm_dbg_kms(display->drm, "Sanitizing CDCLK decimal divider (CDCLK_CTL 0x%x, expected 0x%x)\n", intel_de_read(display, CDCLK_CTL), expected); @@ -2388,8 +2406,6 @@ static void bxt_sanitize_cdclk(struct intel_display *display) return; sanitize: - drm_dbg_kms(display->drm, "Sanitizing cdclk programmed by pre-os\n"); - /* force cdclk programming */ display->cdclk.hw.cdclk = 0; diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.c b/drivers/gpu/drm/i915/display/intel_cmtg.c index e1fdc6fe9762..c8e0f90af910 100644 --- a/drivers/gpu/drm/i915/display/intel_cmtg.c +++ b/drivers/gpu/drm/i915/display/intel_cmtg.c @@ -4,7 +4,6 @@ */ #include -#include #include #include @@ -13,9 +12,14 @@ #include "intel_cmtg_regs.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_display.h" #include "intel_display_device.h" +#include "intel_display_irq.h" #include "intel_display_power.h" #include "intel_display_regs.h" +#include "intel_display_types.h" +#include "intel_vrr.h" +#include "intel_vrr_regs.h" /** * DOC: Common Primary Timing Generator (CMTG) @@ -81,6 +85,18 @@ static void intel_cmtg_dump_config(struct intel_display *display, str_yes_no(cmtg_config->trans_b_secondary)); } +static inline enum transcoder to_cmtg_transcoder(enum transcoder cpu_transcoder) +{ + switch (cpu_transcoder) { + case TRANSCODER_A: + return TRANSCODER_CMTG0; + case TRANSCODER_B: + return TRANSCODER_CMTG1; + default: + return INVALID_TRANSCODER; + } +} + static bool intel_cmtg_transcoder_is_secondary(struct intel_display *display, enum transcoder trans) { @@ -103,11 +119,11 @@ static void intel_cmtg_get_config(struct intel_display *display, { u32 val; - val = intel_de_read(display, TRANS_CMTG_CTL_A); + val = intel_de_read(display, TRANS_CMTG_CTL(TRANSCODER_A)); cmtg_config->cmtg_a_enable = val & CMTG_ENABLE; if (intel_cmtg_has_cmtg_b(display)) { - val = intel_de_read(display, TRANS_CMTG_CTL_B); + val = intel_de_read(display, TRANS_CMTG_CTL(TRANSCODER_B)); cmtg_config->cmtg_b_enable = val & CMTG_ENABLE; } @@ -124,8 +140,8 @@ static bool intel_cmtg_disable_requires_modeset(struct intel_display *display, return cmtg_config->trans_a_secondary || cmtg_config->trans_b_secondary; } -static void intel_cmtg_disable(struct intel_display *display, - struct intel_cmtg_config *cmtg_config) +static void intel_cmtg_disable_all(struct intel_display *display, + struct intel_cmtg_config *cmtg_config) { u32 clk_sel_clr = 0; u32 clk_sel_set = 0; @@ -140,14 +156,14 @@ static void intel_cmtg_disable(struct intel_display *display, if (cmtg_config->cmtg_a_enable) { drm_dbg_kms(display->drm, "Disabling CMTG A\n"); - intel_de_rmw(display, TRANS_CMTG_CTL_A, CMTG_ENABLE, 0); + intel_de_rmw(display, TRANS_CMTG_CTL(TRANSCODER_A), CMTG_ENABLE, 0); clk_sel_clr |= CMTG_CLK_SEL_A_MASK; clk_sel_set |= CMTG_CLK_SEL_A_DISABLED; } if (cmtg_config->cmtg_b_enable) { drm_dbg_kms(display->drm, "Disabling CMTG B\n"); - intel_de_rmw(display, TRANS_CMTG_CTL_B, CMTG_ENABLE, 0); + intel_de_rmw(display, TRANS_CMTG_CTL(TRANSCODER_B), CMTG_ENABLE, 0); clk_sel_clr |= CMTG_CLK_SEL_B_MASK; clk_sel_set |= CMTG_CLK_SEL_B_DISABLED; } @@ -156,6 +172,57 @@ static void intel_cmtg_disable(struct intel_display *display, intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, clk_sel_set); } +void intel_cmtg_disable(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + enum transcoder cmtg_transcoder = to_cmtg_transcoder(crtc_state->cpu_transcoder); + u32 clk_sel_clr = 0, interrupt_mask = 0; + + if (!crtc->cmtg.enabled) + return; + + if (drm_WARN_ON(display->drm, cmtg_transcoder == INVALID_TRANSCODER)) + return; + + crtc->cmtg.enabled = false; + intel_de_rmw(display, TRANS_VRR_CTL(display, cmtg_transcoder), + VRR_CTL_VRR_ENABLE | VRR_CTL_FLIP_LINE_EN, 0); + + /* + * Use cpu_transcoder for: + * 1. Exclusive CMTG registers that do not use the standard transcoder offset + * (e.g., TRANS_CMTG_CTL, CMTG_CLK_SEL). + * 2. Registers shared between the eDP and CMTG transcoders. + * (e.g., TRANS_DDI_FUNC_CTL2). + */ + + intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(display, cpu_transcoder), + CMTG_SECONDARY_MODE, 0); + intel_de_rmw(display, CMTG_SCANLINE_GB1(cpu_transcoder), CMTG_HW_GB_ENABLE, 0); + + intel_de_rmw(display, TRANS_CMTG_CTL(cpu_transcoder), CMTG_ENABLE, 0); + + if (intel_de_wait_for_clear_ms(display, TRANS_CMTG_CTL(cpu_transcoder), CMTG_STATE, 50)) { + drm_WARN(display->drm, 1, "CMTG: %s disable timeout\n", + transcoder_name(cpu_transcoder)); + return; + } + + clk_sel_clr = cpu_transcoder == TRANSCODER_A ? CMTG_CLK_SEL_A_MASK : CMTG_CLK_SEL_B_MASK; + intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, 0); + + drm_dbg_kms(display->drm, "CMTG: %s disabled\n", transcoder_name(cpu_transcoder)); + + if (cpu_transcoder == TRANSCODER_A) + interrupt_mask = CMTG_VBLANK_A; + else if (cpu_transcoder == TRANSCODER_B) + interrupt_mask = CMTG_VBLANK_B; + + intel_display_irq_port_interrupt_mask(display, interrupt_mask, true); +} + /* * Read out CMTG configuration and, on platforms that allow disabling it without * a modeset, do it. @@ -183,5 +250,202 @@ void intel_cmtg_sanitize(struct intel_display *display) if (intel_cmtg_disable_requires_modeset(display, &cmtg_config)) return; - intel_cmtg_disable(display, &cmtg_config); + intel_cmtg_disable_all(display, &cmtg_config); +} + +bool intel_cmtg_is_allowed(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + + if ((cpu_transcoder == TRANSCODER_A || cpu_transcoder == TRANSCODER_B) && + DISPLAY_VER(display) == 35 && intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP)) + return true; + + return false; +} + +void intel_cmtg_set_clk_select(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 clk_sel_clr = 0; + u32 clk_sel_set = 0; + + if (!intel_cmtg_is_allowed(crtc_state)) + return; + + if (cpu_transcoder == TRANSCODER_A) { + clk_sel_clr = CMTG_CLK_SEL_A_MASK; + clk_sel_set = CMTG_CLK_SELECT_PHYA_ENABLE; + } else if (cpu_transcoder == TRANSCODER_B) { + clk_sel_clr = CMTG_CLK_SEL_B_MASK; + clk_sel_set = CMTG_CLK_SELECT_PHYB_ENABLE; + } + + if (clk_sel_set) + intel_de_rmw(display, CMTG_CLK_SEL, clk_sel_clr, clk_sel_set); +} + +void intel_cmtg_set_timings(const struct intel_crtc_state *crtc_state, enum set_timing_type type) +{ + enum transcoder cmtg_transcoder = to_cmtg_transcoder(crtc_state->cpu_transcoder); + + if (cmtg_transcoder == INVALID_TRANSCODER) + return; + + if (!intel_cmtg_is_allowed(crtc_state)) + return; + + if (type == LRR) + intel_set_transcoder_timings_lrr(crtc_state, cmtg_transcoder); + else + intel_set_transcoder_timings(crtc_state, cmtg_transcoder); +} + +void intel_cmtg_set_vrr_timings(const struct intel_crtc_state *crtc_state) +{ + enum transcoder cmtg_transcoder = to_cmtg_transcoder(crtc_state->cpu_transcoder); + + if (!intel_cmtg_is_allowed(crtc_state)) + return; + + intel_vrr_set_fixed_rr_timings(crtc_state, cmtg_transcoder); +} + +void intel_cmtg_set_vrr_ctl(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder cmtg_transcoder = to_cmtg_transcoder(crtc_state->cpu_transcoder); + u32 vrr_ctl; + + if (!intel_cmtg_is_allowed(crtc_state)) + return; + + vrr_ctl = VRR_CTL_VRR_ENABLE | VRR_CTL_FLIP_LINE_EN | + XELPD_VRR_CTL_VRR_GUARDBAND(crtc_state->vrr.guardband); + + /* TODO: The code below may need to be revisited once CMRR is enabled */ + if (crtc_state->cmrr.enable) + vrr_ctl |= VRR_CTL_CMRR_ENABLE; + + intel_de_write(display, TRANS_VRR_CTL(display, cmtg_transcoder), vrr_ctl); +} + +void intel_cmtg_set_m_n(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder cmtg_transcoder = to_cmtg_transcoder(crtc_state->cpu_transcoder); + const struct intel_link_m_n *m_n = &crtc_state->dp_m_n; + + if (!intel_cmtg_is_allowed(crtc_state)) + return; + + intel_de_write(display, PIPE_LINK_M1(display, cmtg_transcoder), m_n->link_m); + intel_de_write(display, PIPE_LINK_N1(display, cmtg_transcoder), m_n->link_n); +} + +static void intel_cmtg_enable_sync(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 cmtg_ctl; + + cmtg_ctl = CMTG_SYNC_TO_PORT | CMTG_ENABLE; + + intel_de_rmw(display, TRANS_CMTG_CTL(cpu_transcoder), 0, cmtg_ctl); + if (intel_de_wait_for_clear_ms(display, TRANS_CMTG_CTL(cpu_transcoder), + CMTG_SYNC_TO_PORT, 50)) { + drm_WARN(display->drm, 1, "CMTG: %s enable timeout\n", + transcoder_name(cpu_transcoder)); + } +} + +static void intel_cmtg_enable_ddi(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 interrupt_mask = 0; + + intel_de_rmw(display, TRANS_DDI_FUNC_CTL2(display, cpu_transcoder), 0, CMTG_SECONDARY_MODE); + intel_de_rmw(display, CMTG_SCANLINE_GB1(cpu_transcoder), 0, CMTG_HW_GB_ENABLE); + crtc->cmtg.enabled = true; + drm_dbg_kms(display->drm, "CMTG: %s enabled\n", transcoder_name(cpu_transcoder)); + + /* + * TODO: Currently cmtg is enabled along with eDP transcoder so cmtg + * interrupt is not enabled through IER, need to do some fine + * tuning in future. + */ + + if (cpu_transcoder == TRANSCODER_A) + interrupt_mask = CMTG_VBLANK_A; + else if (cpu_transcoder == TRANSCODER_B) + interrupt_mask = CMTG_VBLANK_B; + + intel_display_irq_port_interrupt_mask(display, interrupt_mask, false); +} + +/* Bspec: 75253 */ +#define DC3CO_ENTRY_LATENCY_US 55 +#define DC3CO_EXIT_LATENCY_US 40 + +static void intel_cmtg_set_hwgb(const struct intel_crtc_state *crtc_state) +{ + struct intel_display *display = to_intel_display(crtc_state); + enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; + u32 breakeven_gb; + u32 dc5_exit_latency; + u32 line_time_us = 75; /* Max default initialization value */ + u32 val; + + if (crtc_state->linetime) + line_time_us = DIV_ROUND_UP(crtc_state->linetime, 8); + + /* Break Even Guardband - DC3co Entry Latency / linetime */ + breakeven_gb = DIV_ROUND_UP(DC3CO_ENTRY_LATENCY_US, line_time_us); + + /* DC5 Exit Latency - DC3co Exit Latency / linetime */ + dc5_exit_latency = DIV_ROUND_UP(DC3CO_EXIT_LATENCY_US, line_time_us); + + val = REG_FIELD_PREP(CMTG_HW_GB_BREAKEVEN_MASK, breakeven_gb) | + REG_FIELD_PREP(CMTG_HW_GB_DC5_EXIT_LATENCY_MASK, dc5_exit_latency) | + REG_FIELD_PREP(CMTG_HW_GB_UP_LW_BG_DIFF_MASK, 1); + + intel_de_write(display, CMTG_HW_GB(cpu_transcoder), val); +} + +static void intel_cmtg_restore(const struct intel_crtc_state *crtc_state) +{ + intel_cmtg_set_clk_select(crtc_state); + intel_cmtg_set_timings(crtc_state, MODESET); + intel_cmtg_set_vrr_timings(crtc_state); + intel_cmtg_set_vrr_ctl(crtc_state); + intel_cmtg_set_m_n(crtc_state); +} + +void intel_cmtg_program(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + struct intel_crtc *crtc; + struct intel_crtc_state *new_crtc_state; + bool dc3co_to_dc6 = intel_display_power_get_and_reset_dc3co_to_dc6(display); + + for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state) { + bool modeset = intel_crtc_needs_modeset(new_crtc_state); + + if (!intel_cmtg_is_allowed(new_crtc_state)) + continue; + + if ((modeset || dc3co_to_dc6) && + new_crtc_state->hw.active && !crtc->cmtg.enabled) { + if (dc3co_to_dc6) + intel_cmtg_restore(new_crtc_state); + + intel_cmtg_enable_sync(new_crtc_state); + intel_cmtg_set_hwgb(new_crtc_state); + intel_cmtg_enable_ddi(new_crtc_state); + } + } } diff --git a/drivers/gpu/drm/i915/display/intel_cmtg.h b/drivers/gpu/drm/i915/display/intel_cmtg.h index ba62199adaa2..a08cb2dcee67 100644 --- a/drivers/gpu/drm/i915/display/intel_cmtg.h +++ b/drivers/gpu/drm/i915/display/intel_cmtg.h @@ -6,8 +6,25 @@ #ifndef __INTEL_CMTG_H__ #define __INTEL_CMTG_H__ -struct intel_display; +#include +struct intel_atomic_state; +struct intel_display; +struct intel_crtc_state; + +enum set_timing_type { + MODESET = 0, + LRR +}; + +void intel_cmtg_disable(const struct intel_crtc_state *crtc_state); +void intel_cmtg_set_m_n(const struct intel_crtc_state *crtc_state); +void intel_cmtg_set_vrr_timings(const struct intel_crtc_state *crtc_state); +void intel_cmtg_set_vrr_ctl(const struct intel_crtc_state *crtc_state); +void intel_cmtg_set_timings(const struct intel_crtc_state *crtc_state, enum set_timing_type type); +void intel_cmtg_set_clk_select(const struct intel_crtc_state *crtc_state); void intel_cmtg_sanitize(struct intel_display *display); +bool intel_cmtg_is_allowed(const struct intel_crtc_state *crtc_state); +void intel_cmtg_program(struct intel_atomic_state *state); #endif /* __INTEL_CMTG_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_cmtg_regs.h b/drivers/gpu/drm/i915/display/intel_cmtg_regs.h index 945a35578284..18dcb665df04 100644 --- a/drivers/gpu/drm/i915/display/intel_cmtg_regs.h +++ b/drivers/gpu/drm/i915/display/intel_cmtg_regs.h @@ -10,12 +10,32 @@ #define CMTG_CLK_SEL _MMIO(0x46160) #define CMTG_CLK_SEL_A_MASK REG_GENMASK(31, 29) +#define CMTG_CLK_SELECT_PHYA_ENABLE REG_FIELD_PREP(CMTG_CLK_SEL_A_MASK, 0x4) #define CMTG_CLK_SEL_A_DISABLED REG_FIELD_PREP(CMTG_CLK_SEL_A_MASK, 0) #define CMTG_CLK_SEL_B_MASK REG_GENMASK(15, 13) +#define CMTG_CLK_SELECT_PHYB_ENABLE REG_FIELD_PREP(CMTG_CLK_SEL_B_MASK, 0x6) #define CMTG_CLK_SEL_B_DISABLED REG_FIELD_PREP(CMTG_CLK_SEL_B_MASK, 0) -#define TRANS_CMTG_CTL_A _MMIO(0x6fa88) -#define TRANS_CMTG_CTL_B _MMIO(0x6fb88) +#define _TRANS_CMTG_CTL_A 0x6fa88 +#define _TRANS_CMTG_CTL_B 0x6fb88 +#define TRANS_CMTG_CTL(trans) _MMIO_TRANS((trans), \ + _TRANS_CMTG_CTL_A, _TRANS_CMTG_CTL_B) #define CMTG_ENABLE REG_BIT(31) +#define CMTG_SYNC_TO_PORT REG_BIT(29) +#define CMTG_STATE REG_BIT(23) + +#define _CMTG_HW_GB_A 0x6fa8c +#define _CMTG_HW_GB_B 0x6fb8c +#define CMTG_HW_GB(trans) _MMIO_TRANS((trans), \ + _CMTG_HW_GB_A, _CMTG_HW_GB_B) +#define CMTG_HW_GB_BREAKEVEN_MASK REG_GENMASK(11, 0) +#define CMTG_HW_GB_DC5_EXIT_LATENCY_MASK REG_GENMASK(27, 16) +#define CMTG_HW_GB_UP_LW_BG_DIFF_MASK REG_GENMASK(31, 28) + +#define _CMTG_SCANLINE_GB1_A 0x456A0 +#define _CMTG_SCANLINE_GB1_B 0x456C0 +#define CMTG_SCANLINE_GB1(trans) _MMIO_TRANS((trans), \ + _CMTG_SCANLINE_GB1_A, _CMTG_SCANLINE_GB1_B) +#define CMTG_HW_GB_ENABLE REG_BIT(31) #endif /* __INTEL_CMTG_REGS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_color.c b/drivers/gpu/drm/i915/display/intel_color.c index 7ef870cd9a16..87ced9f6ff40 100644 --- a/drivers/gpu/drm/i915/display/intel_color.c +++ b/drivers/gpu/drm/i915/display/intel_color.c @@ -3967,48 +3967,34 @@ xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb, enum pipe pipe = to_intel_plane(state->plane)->pipe; enum plane_id plane = to_intel_plane(state->plane)->id; const struct drm_color_lut32 *pre_csc_lut = plane_state->hw.degamma_lut->data; - u32 i, lut_size; + int i, lut_size = 128; + u32 lut_val; - if (icl_is_hdr_plane(display, plane)) { - lut_size = 128; + if (!icl_is_hdr_plane(display, plane)) + return; - intel_de_write_dsb(display, dsb, - PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), - PLANE_PAL_PREC_AUTO_INCREMENT); + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), + PLANE_PAL_PREC_AUTO_INCREMENT); + for (i = 0; i < lut_size + 3; i++) { if (pre_csc_lut) { - for (i = 0; i < lut_size; i++) { - u32 lut_val = drm_color_lut32_extract(pre_csc_lut[i].green, 24); - - intel_de_write_dsb(display, dsb, - PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), - lut_val); - } - - /* Program the max register to clamp values > 1.0. */ - /* TODO: Restrict to 0x7ffffff */ - do { - intel_de_write_dsb(display, dsb, - PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), - (1 << 24)); - } while (i++ < 130); + if (i < lut_size) + lut_val = drm_color_lut32_extract(pre_csc_lut[i].green, 24); + /* else duplicate last lut_val */ } else { - for (i = 0; i < lut_size; i++) { - u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1); - - intel_de_write_dsb(display, dsb, - PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), v); - } - - do { - intel_de_write_dsb(display, dsb, - PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), - 1 << 24); - } while (i++ < 130); + if (i < lut_size) + lut_val = (i * ((1 << 24) - 1)) / (lut_size - 1); + else + lut_val = 1 << 24; } - intel_de_write_dsb(display, dsb, PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); + intel_de_write_dsb(display, dsb, + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), + lut_val); } + + intel_de_write_dsb(display, dsb, PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); } static void @@ -4020,51 +4006,38 @@ xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb, enum pipe pipe = to_intel_plane(state->plane)->pipe; enum plane_id plane = to_intel_plane(state->plane)->id; const struct drm_color_lut32 *post_csc_lut = plane_state->hw.gamma_lut->data; - u32 i, lut_size, lut_val; + int i, lut_size = 32; + u32 lut_val; - if (icl_is_hdr_plane(display, plane)) { - intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), - PLANE_PAL_PREC_AUTO_INCREMENT); - /* TODO: Add macro */ - intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), - PLANE_PAL_PREC_AUTO_INCREMENT); + if (!icl_is_hdr_plane(display, plane)) + return; + + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), + PLANE_PAL_PREC_AUTO_INCREMENT); + /* TODO: Add macro */ + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), + PLANE_PAL_PREC_AUTO_INCREMENT); + + for (i = 0; i < lut_size + 3; i++) { if (post_csc_lut) { - lut_size = 32; - for (i = 0; i < lut_size; i++) { + if (i < lut_size) lut_val = drm_color_lut32_extract(post_csc_lut[i].green, 24); - - intel_de_write_dsb(display, dsb, - PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), - lut_val); - } - - /* Segment 2 */ - do { - intel_de_write_dsb(display, dsb, - PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), - (1 << 24)); - } while (i++ < 34); + /* else clamp to the last LUT value to prevent step discontinuity */ } else { - /*TODO: Add for segment 0 */ - lut_size = 32; - for (i = 0; i < lut_size; i++) { - u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1); - - intel_de_write_dsb(display, dsb, - PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), v); - } - - do { - intel_de_write_dsb(display, dsb, - PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), - 1 << 24); - } while (i++ < 34); + if (i < lut_size) + lut_val = (i * ((1 << 24) - 1)) / (lut_size - 1); + else + lut_val = 1 << 24; } - intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); intel_de_write_dsb(display, dsb, - PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), 0); + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), + lut_val); } + + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); + intel_de_write_dsb(display, dsb, + PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), 0); } static void diff --git a/drivers/gpu/drm/i915/display/intel_crt.c b/drivers/gpu/drm/i915/display/intel_crt.c index 243e332bef57..5b8968197fbc 100644 --- a/drivers/gpu/drm/i915/display/intel_crt.c +++ b/drivers/gpu/drm/i915/display/intel_crt.c @@ -397,7 +397,8 @@ intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static int intel_crt_compute_config(struct intel_encoder *encoder, +static int intel_crt_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { @@ -413,7 +414,8 @@ static int intel_crt_compute_config(struct intel_encoder *encoder, return 0; } -static int pch_crt_compute_config(struct intel_encoder *encoder, +static int pch_crt_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { @@ -432,7 +434,8 @@ static int pch_crt_compute_config(struct intel_encoder *encoder, return 0; } -static int hsw_crt_compute_config(struct intel_encoder *encoder, +static int hsw_crt_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { diff --git a/drivers/gpu/drm/i915/display/intel_cursor.c b/drivers/gpu/drm/i915/display/intel_cursor.c index 52347668f27d..88384dea868b 100644 --- a/drivers/gpu/drm/i915/display/intel_cursor.c +++ b/drivers/gpu/drm/i915/display/intel_cursor.c @@ -876,7 +876,7 @@ intel_legacy_cursor_update(struct drm_plane *_plane, new_plane_state->uapi.crtc_w = crtc_w; new_plane_state->uapi.crtc_h = crtc_h; - intel_plane_copy_uapi_to_hw_state(new_plane_state, new_plane_state, crtc); + intel_plane_copy_uapi_to_hw_state(NULL, new_plane_state, new_plane_state, crtc); ret = intel_plane_atomic_check_with_state(crtc_state, new_crtc_state, old_plane_state, new_plane_state); diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.c b/drivers/gpu/drm/i915/display/intel_cx0_phy.c index 24a51ab21b55..452062417ce9 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.c +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.c @@ -9,6 +9,7 @@ #include #include "intel_alpm.h" +#include "intel_cmtg.h" #include "intel_cx0_phy.h" #include "intel_cx0_phy_regs.h" #include "intel_display_regs.h" @@ -3418,10 +3419,20 @@ void intel_mtl_pll_enable(struct intel_encoder *encoder, void intel_mtl_pll_enable_clock(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state) { + struct intel_display *display = to_intel_display(encoder); struct intel_digital_port *dig_port = enc_to_dig_port(encoder); if (intel_tc_port_in_tbt_alt_mode(dig_port)) intel_mtl_tbt_pll_enable_clock(encoder, crtc_state->port_clock); + + /* + * CMTG can be enabled only when the transcoder and port are compatible + * (transcoder A with port A, transcoder B with port B). + */ + if (HAS_LT_PHY(display) && + ((crtc_state->cpu_transcoder == TRANSCODER_A && encoder->port == PORT_A) || + (crtc_state->cpu_transcoder == TRANSCODER_B && encoder->port == PORT_B))) + intel_cmtg_set_clk_select(crtc_state); } /* diff --git a/drivers/gpu/drm/i915/display/intel_cx0_phy.h b/drivers/gpu/drm/i915/display/intel_cx0_phy.h index 1428e7a5a318..95c20eb4b4b7 100644 --- a/drivers/gpu/drm/i915/display/intel_cx0_phy.h +++ b/drivers/gpu/drm/i915/display/intel_cx0_phy.h @@ -60,7 +60,6 @@ void intel_cx0_phy_set_signal_levels(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state); void intel_cx0_powerdown_change_sequence(struct intel_encoder *encoder, u8 lane_mask, u8 state); -int intel_cx0_phy_check_hdmi_link_rate(struct intel_hdmi *hdmi, int clock); void intel_cx0_setup_powerdown(struct intel_encoder *encoder); bool intel_cx0_is_hdmi_frl(u32 clock); u8 intel_cx0_read(struct intel_encoder *encoder, u8 lane_mask, u16 addr); diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index 6296635c4e79..2b7eb010511b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -3501,6 +3501,8 @@ static void intel_ddi_enable_hdmi(struct intel_atomic_state *state, } intel_ddi_buf_enable(encoder, buf_ctl); + + intel_hdmi_poll_for_scrambling_enable(crtc_state, connector); } static void intel_ddi_enable(struct intel_atomic_state *state, @@ -4483,7 +4485,8 @@ intel_ddi_compute_output_type(struct intel_encoder *encoder, } } -static int intel_ddi_compute_config(struct intel_encoder *encoder, +static int intel_ddi_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { @@ -4501,7 +4504,7 @@ static int intel_ddi_compute_config(struct intel_encoder *encoder, ret = intel_hdmi_compute_config(encoder, pipe_config, conn_state); } else { - ret = intel_dp_compute_config(encoder, pipe_config, conn_state); + ret = intel_dp_compute_config(state, encoder, pipe_config, conn_state); } if (ret) @@ -4606,7 +4609,8 @@ intel_ddi_port_sync_transcoders(const struct intel_crtc_state *ref_crtc_state, return transcoders; } -static int intel_ddi_compute_config_late(struct intel_encoder *encoder, +static int intel_ddi_compute_config_late(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { @@ -4659,6 +4663,7 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder) drm_encoder_cleanup(encoder); kfree(dig_port->hdcp.port_data.streams); + intel_dp_link_cleanup(&dig_port->dp); kfree(dig_port); } @@ -4696,11 +4701,16 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port) struct intel_display *display = to_intel_display(dig_port); struct intel_connector *connector; enum port port = dig_port->base.port; + int err; connector = intel_connector_alloc(); if (!connector) return -ENOMEM; + err = intel_dp_link_init(&dig_port->dp); + if (err) + goto err_dp_init; + dig_port->dp.output_reg = DDI_BUF_CTL(port); if (DISPLAY_VER(display) >= 14) dig_port->dp.prepare_link_retrain = mtl_ddi_prepare_link_retrain; @@ -4713,8 +4723,9 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port) dig_port->dp.preemph_max = intel_ddi_dp_preemph_max; if (!intel_dp_init_connector(dig_port, connector)) { - kfree(connector); - return -EINVAL; + err = -EINVAL; + + goto err_init_connector; } if (dig_port->base.type == INTEL_OUTPUT_EDP) { @@ -4730,6 +4741,13 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port) } return 0; + +err_init_connector: + intel_dp_link_cleanup(&dig_port->dp); +err_dp_init: + kfree(connector); + + return err; } static void intel_ddi_cleanup_dp_connector(struct intel_digital_port *dig_port) @@ -4738,6 +4756,7 @@ static void intel_ddi_cleanup_dp_connector(struct intel_digital_port *dig_port) struct intel_connector *connector = intel_dp->attached_connector; intel_dp_cleanup_connector(dig_port, connector); + intel_dp_link_cleanup(intel_dp); kfree(connector); } diff --git a/drivers/gpu/drm/i915/display/intel_de.c b/drivers/gpu/drm/i915/display/intel_de.c index 6daee9e82503..a7417905192d 100644 --- a/drivers/gpu/drm/i915/display/intel_de.c +++ b/drivers/gpu/drm/i915/display/intel_de.c @@ -9,11 +9,11 @@ #include "intel_de.h" -static int __intel_de_wait_for_register(struct intel_display *display, - intel_reg_t reg, u32 mask, u32 value, - unsigned int timeout_us, - u32 (*read)(struct intel_display *display, intel_reg_t reg), - u32 *out_val, bool is_atomic) +static int intel_de_wait_for_register(struct intel_display *display, + intel_reg_t reg, u32 mask, u32 value, + unsigned int timeout_us, + u32 (*read)(struct intel_display *display, intel_reg_t reg), + u32 *out_val, bool is_atomic) { const ktime_t end = ktime_add_us(ktime_get_raw(), timeout_us); int wait_max = 1000; @@ -60,28 +60,6 @@ static int __intel_de_wait_for_register(struct intel_display *display, return ret; } -static int intel_de_wait_for_register(struct intel_display *display, - intel_reg_t reg, u32 mask, u32 value, - unsigned int fast_timeout_us, - unsigned int slow_timeout_us, - u32 (*read)(struct intel_display *display, intel_reg_t reg), - u32 *out_value, bool is_atomic) -{ - int ret = -EINVAL; - - if (fast_timeout_us) - ret = __intel_de_wait_for_register(display, reg, mask, value, - fast_timeout_us, read, - out_value, is_atomic); - - if (ret && slow_timeout_us) - ret = __intel_de_wait_for_register(display, reg, mask, value, - slow_timeout_us, read, - out_value, is_atomic); - - return ret; -} - int intel_de_wait_us(struct intel_display *display, intel_reg_t reg, u32 mask, u32 value, unsigned int timeout_us, u32 *out_value) @@ -91,7 +69,7 @@ int intel_de_wait_us(struct intel_display *display, intel_reg_t reg, intel_dmc_wl_get(display, reg); ret = intel_de_wait_for_register(display, reg, mask, value, - timeout_us, 0, + timeout_us, intel_de_read, out_value, false); @@ -109,7 +87,7 @@ int intel_de_wait_ms(struct intel_display *display, intel_reg_t reg, intel_dmc_wl_get(display, reg); ret = intel_de_wait_for_register(display, reg, mask, value, - 2, timeout_ms * 1000, + timeout_ms * 1000, intel_de_read, out_value, false); @@ -123,7 +101,7 @@ int intel_de_wait_fw_ms(struct intel_display *display, intel_reg_t reg, u32 *out_value) { return intel_de_wait_for_register(display, reg, mask, value, - 2, timeout_ms * 1000, + timeout_ms * 1000, intel_de_read_fw, out_value, false); } @@ -133,7 +111,7 @@ int intel_de_wait_fw_us_atomic(struct intel_display *display, intel_reg_t reg, u32 *out_value) { return intel_de_wait_for_register(display, reg, mask, value, - timeout_us, 0, + timeout_us, intel_de_read_fw, out_value, true); } diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 8e269b71f18e..90c05ad08f86 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -60,6 +60,7 @@ #include "intel_bw.h" #include "intel_cdclk.h" #include "intel_clock_gating.h" +#include "intel_cmtg.h" #include "intel_color.h" #include "intel_crt.h" #include "intel_crtc.h" @@ -132,7 +133,6 @@ #include "vlv_dsi_pll.h" #include "vlv_dsi_regs.h" -static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state); static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state); static void hsw_set_transconf(const struct intel_crtc_state *crtc_state); static void bdw_set_pipe_misc(struct intel_dsb *dsb, @@ -1504,7 +1504,7 @@ static void ilk_configure_cpu_transcoder(const struct intel_crtc_state *crtc_sta &crtc_state->dp_m2_n2); } - intel_set_transcoder_timings(crtc_state); + intel_set_transcoder_timings(crtc_state, crtc_state->cpu_transcoder); ilk_set_pipeconf(crtc_state); } @@ -1635,7 +1635,9 @@ static void hsw_configure_cpu_transcoder(const struct intel_crtc_state *crtc_sta &crtc_state->dp_m2_n2); } - intel_set_transcoder_timings(crtc_state); + intel_cmtg_set_m_n(crtc_state); + intel_set_transcoder_timings(crtc_state, crtc_state->cpu_transcoder); + intel_cmtg_set_timings(crtc_state, MODESET); if (cpu_transcoder != TRANSCODER_EDP) intel_de_write(display, TRANS_MULT(display, cpu_transcoder), @@ -1788,6 +1790,10 @@ static void hsw_crtc_disable(struct intel_atomic_state *state, intel_atomic_get_old_crtc_state(state, crtc); struct intel_crtc *pipe_crtc; + if (crtc->cmtg.enabled && intel_cmtg_is_allowed(old_crtc_state)) { + intel_cmtg_set_clk_select(old_crtc_state); + intel_cmtg_disable(old_crtc_state); + } /* * FIXME collapse everything to one hook. * Need care with mst->ddi interactions. @@ -2048,7 +2054,7 @@ static void i9xx_configure_cpu_transcoder(const struct intel_crtc_state *crtc_st &crtc_state->dp_m2_n2); } - intel_set_transcoder_timings(crtc_state); + intel_set_transcoder_timings(crtc_state, crtc_state->cpu_transcoder); i9xx_set_pipeconf(crtc_state); } @@ -2664,17 +2670,17 @@ transcoder_has_vrr(const struct intel_crtc_state *crtc_state) return HAS_VRR(display) && !transcoder_is_dsi(cpu_transcoder); } -static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state) +void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state, + enum transcoder transcoder) { struct intel_display *display = to_intel_display(crtc_state); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); enum pipe pipe = crtc->pipe; - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; u32 crtc_vdisplay, crtc_vtotal, crtc_vblank_start, crtc_vblank_end; int vsyncshift = 0; - drm_WARN_ON(display->drm, transcoder_is_dsi(cpu_transcoder)); + drm_WARN_ON(display->drm, transcoder_is_dsi(transcoder)); /* We need to be careful not to changed the adjusted mode, for otherwise * the hw state checker will get angry at the mismatch. */ @@ -2703,7 +2709,7 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta */ if (DISPLAY_VER(display) >= 13) { intel_de_write(display, - TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder), + TRANS_SET_CONTEXT_LATENCY(display, transcoder), crtc_state->set_context_latency); /* @@ -2718,35 +2724,26 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta if (DISPLAY_VER(display) >= 4 && DISPLAY_VER(display) < 35) intel_de_write(display, - TRANS_VSYNCSHIFT(display, cpu_transcoder), + TRANS_VSYNCSHIFT(display, transcoder), vsyncshift); - intel_de_write(display, TRANS_HTOTAL(display, cpu_transcoder), + intel_de_write(display, TRANS_HTOTAL(display, transcoder), HACTIVE(adjusted_mode->crtc_hdisplay - 1) | HTOTAL(adjusted_mode->crtc_htotal - 1)); - intel_de_write(display, TRANS_HBLANK(display, cpu_transcoder), + intel_de_write(display, TRANS_HBLANK(display, transcoder), HBLANK_START(adjusted_mode->crtc_hblank_start - 1) | HBLANK_END(adjusted_mode->crtc_hblank_end - 1)); - intel_de_write(display, TRANS_HSYNC(display, cpu_transcoder), + intel_de_write(display, TRANS_HSYNC(display, transcoder), HSYNC_START(adjusted_mode->crtc_hsync_start - 1) | HSYNC_END(adjusted_mode->crtc_hsync_end - 1)); - /* - * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal - * bits are not required. Since the support for these bits is going to - * be deprecated in upcoming platforms, avoid writing these bits for the - * platforms that do not use legacy Timing Generator. - */ - if (intel_vrr_always_use_vrr_tg(display)) - crtc_vtotal = 1; - - intel_de_write(display, TRANS_VTOTAL(display, cpu_transcoder), + intel_de_write(display, TRANS_VTOTAL(display, transcoder), VACTIVE(crtc_vdisplay - 1) | VTOTAL(crtc_vtotal - 1)); - intel_de_write(display, TRANS_VBLANK(display, cpu_transcoder), + intel_de_write(display, TRANS_VBLANK(display, transcoder), VBLANK_START(crtc_vblank_start - 1) | VBLANK_END(crtc_vblank_end - 1)); - intel_de_write(display, TRANS_VSYNC(display, cpu_transcoder), + intel_de_write(display, TRANS_VSYNC(display, transcoder), VSYNC_START(adjusted_mode->crtc_vsync_start - 1) | VSYNC_END(adjusted_mode->crtc_vsync_end - 1)); @@ -2754,13 +2751,15 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta * programmed with the VTOTAL_EDP value. Same for VTOTAL_C. This is * documented on the DDI_FUNC_CTL register description, EDP Input Select * bits. */ - if (display->platform.haswell && cpu_transcoder == TRANSCODER_EDP && + if (display->platform.haswell && transcoder == TRANSCODER_EDP && (pipe == PIPE_B || pipe == PIPE_C)) intel_de_write(display, TRANS_VTOTAL(display, pipe), VACTIVE(crtc_vdisplay - 1) | VTOTAL(crtc_vtotal - 1)); - if (DISPLAY_VER(display) >= 30) { + if (DISPLAY_VER(display) >= 30 && + transcoder != TRANSCODER_CMTG0 && + transcoder != TRANSCODER_CMTG1) { /* * Address issues for resolutions with high refresh rate that * have small Hblank, specifically where Hblank is smaller than @@ -2769,19 +2768,19 @@ static void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_sta * followed by BE which DPRX devices are unable to handle. * https://groups.vesa.org/wg/DP/document/20494 */ - intel_de_write(display, DP_MIN_HBLANK_CTL(cpu_transcoder), + intel_de_write(display, DP_MIN_HBLANK_CTL(transcoder), crtc_state->min_hblank); } } -static void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc_state) +void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc_state, + enum transcoder transcoder) { struct intel_display *display = to_intel_display(crtc_state); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; const struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; u32 crtc_vdisplay, crtc_vtotal, crtc_vblank_start, crtc_vblank_end; - drm_WARN_ON(display->drm, transcoder_is_dsi(cpu_transcoder)); + drm_WARN_ON(display->drm, transcoder_is_dsi(transcoder)); crtc_vdisplay = adjusted_mode->crtc_vdisplay; crtc_vtotal = adjusted_mode->crtc_vtotal; @@ -2796,7 +2795,7 @@ static void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc if (DISPLAY_VER(display) >= 13) { intel_de_write(display, - TRANS_SET_CONTEXT_LATENCY(display, cpu_transcoder), + TRANS_SET_CONTEXT_LATENCY(display, transcoder), crtc_state->set_context_latency); /* @@ -2813,28 +2812,27 @@ static void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc * The hardware actually ignores TRANS_VBLANK.VBLANK_END in DP mode. * But let's write it anyway to keep the state checker happy. */ - intel_de_write(display, TRANS_VBLANK(display, cpu_transcoder), + intel_de_write(display, TRANS_VBLANK(display, transcoder), VBLANK_START(crtc_vblank_start - 1) | VBLANK_END(crtc_vblank_end - 1)); + /* - * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal - * bits are not required. Since the support for these bits is going to - * be deprecated in upcoming platforms, avoid writing these bits for the - * platforms that do not use legacy Timing Generator. + * DP doesn't have vertical sync, so TRANS_VSYNC only affects + * the position of the vsync interrupt (and does so even when + * using the VRR timing generator!). Thus updating TRANS_VSYNC + * here seems fine even if it isn't double buffered. */ - if (intel_vrr_always_use_vrr_tg(display)) - crtc_vtotal = 1; + intel_de_write(display, TRANS_VSYNC(display, transcoder), + VSYNC_START(adjusted_mode->crtc_vsync_start - 1) | + VSYNC_END(adjusted_mode->crtc_vsync_end - 1)); /* * The double buffer latch point for TRANS_VTOTAL * is the transcoder's undelayed vblank. */ - intel_de_write(display, TRANS_VTOTAL(display, cpu_transcoder), + intel_de_write(display, TRANS_VTOTAL(display, transcoder), VACTIVE(crtc_vdisplay - 1) | VTOTAL(crtc_vtotal - 1)); - - intel_vrr_set_fixed_rr_timings(crtc_state); - intel_vrr_transcoder_enable(crtc_state); } static void intel_set_pipe_src_size(const struct intel_crtc_state *crtc_state) @@ -4783,7 +4781,7 @@ intel_modeset_pipe_config(struct intel_atomic_state *state, if (connector_state->crtc != &crtc->base) continue; - ret = encoder->compute_config(encoder, crtc_state, + ret = encoder->compute_config(state, encoder, crtc_state, connector_state); if (ret == -EDEADLK) return ret; @@ -4843,7 +4841,7 @@ intel_modeset_pipe_config_late(struct intel_atomic_state *state, !encoder->compute_config_late) continue; - ret = encoder->compute_config_late(encoder, crtc_state, + ret = encoder->compute_config_late(state, encoder, crtc_state, conn_state); if (ret) return ret; @@ -5189,9 +5187,9 @@ intel_pipe_config_compare(const struct intel_crtc_state *current_config, PIPE_CONF_CHECK_I(name.crtc_vdisplay); \ if (!fastset || !allow_vblank_delay_fastset(current_config)) \ PIPE_CONF_CHECK_I(name.crtc_vblank_start); \ - PIPE_CONF_CHECK_I(name.crtc_vsync_start); \ - PIPE_CONF_CHECK_I(name.crtc_vsync_end); \ if (!fastset || !pipe_config->update_lrr) { \ + PIPE_CONF_CHECK_I(name.crtc_vsync_start); \ + PIPE_CONF_CHECK_I(name.crtc_vsync_end); \ PIPE_CONF_CHECK_I(name.crtc_vtotal); \ PIPE_CONF_CHECK_I(name.crtc_vblank_end); \ } \ @@ -5658,35 +5656,43 @@ int intel_modeset_all_pipes_late(struct intel_atomic_state *state, return 0; } +int intel_modeset_commit_pipes_for_atomic_state(struct intel_atomic_state *state, + u8 pipe_mask, + struct drm_modeset_acquire_ctx *ctx) +{ + struct intel_display *display = to_intel_display(state); + struct intel_crtc *crtc; + + state->base.acquire_ctx = ctx; + state->internal = true; + + for_each_intel_crtc_in_pipe_mask(display, crtc, pipe_mask) { + struct intel_crtc_state *crtc_state = + intel_atomic_get_crtc_state(&state->base, crtc); + + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + crtc_state->uapi.connectors_changed = true; + } + + return drm_atomic_commit(&state->base); +} + int intel_modeset_commit_pipes(struct intel_display *display, u8 pipe_mask, struct drm_modeset_acquire_ctx *ctx) { struct drm_atomic_commit *state; - struct intel_crtc *crtc; int ret; state = drm_atomic_commit_alloc(display->drm); if (!state) return -ENOMEM; - state->acquire_ctx = ctx; - to_intel_atomic_state(state)->internal = true; + ret = intel_modeset_commit_pipes_for_atomic_state(to_intel_atomic_state(state), + pipe_mask, ctx); - for_each_intel_crtc_in_pipe_mask(display, crtc, pipe_mask) { - struct intel_crtc_state *crtc_state = - intel_atomic_get_crtc_state(state, crtc); - - if (IS_ERR(crtc_state)) { - ret = PTR_ERR(crtc_state); - goto out; - } - - crtc_state->uapi.connectors_changed = true; - } - - ret = drm_atomic_commit(state); -out: drm_atomic_commit_put(state); return ret; @@ -5805,6 +5811,8 @@ static bool lrr_params_changed(const struct intel_crtc_state *old_crtc_state, return old_adjusted_mode->crtc_vblank_start != new_adjusted_mode->crtc_vblank_start || old_adjusted_mode->crtc_vblank_end != new_adjusted_mode->crtc_vblank_end || + old_adjusted_mode->crtc_vsync_start != new_adjusted_mode->crtc_vsync_start || + old_adjusted_mode->crtc_vsync_end != new_adjusted_mode->crtc_vsync_end || old_adjusted_mode->crtc_vtotal != new_adjusted_mode->crtc_vtotal || old_crtc_state->set_context_latency != new_crtc_state->set_context_latency; } @@ -6667,12 +6675,19 @@ static void intel_pipe_fastset(const struct intel_crtc_state *old_crtc_state, display->platform.broadwell || display->platform.haswell) hsw_set_linetime_wm(new_crtc_state); - if (new_crtc_state->update_m_n) + if (new_crtc_state->update_m_n) { intel_cpu_transcoder_set_m1_n1(crtc, new_crtc_state->cpu_transcoder, &new_crtc_state->dp_m_n); + intel_cmtg_set_m_n(new_crtc_state); + } - if (new_crtc_state->update_lrr) - intel_set_transcoder_timings_lrr(new_crtc_state); + if (new_crtc_state->update_lrr) { + intel_set_transcoder_timings_lrr(new_crtc_state, new_crtc_state->cpu_transcoder); + intel_cmtg_set_timings(new_crtc_state, LRR); + intel_vrr_set_fixed_rr_timings(new_crtc_state, new_crtc_state->cpu_transcoder); + intel_cmtg_set_vrr_timings(new_crtc_state); + intel_vrr_transcoder_enable(new_crtc_state); + } } static void commit_pipe_pre_planes(struct intel_atomic_state *state, @@ -6870,6 +6885,12 @@ static void intel_update_crtc(struct intel_atomic_state *state, if (intel_crtc_needs_fastset(new_crtc_state) && old_crtc_state->inherited) intel_crtc_arm_fifo_underrun(crtc, new_crtc_state); + + if (crtc->cmtg.enabled && intel_crtc_vrr_enabling(state, crtc) && + intel_cmtg_is_allowed(new_crtc_state)) { + intel_cmtg_set_clk_select(new_crtc_state); + intel_cmtg_disable(new_crtc_state); + } } static void intel_old_crtc_state_disables(struct intel_atomic_state *state, @@ -7428,6 +7449,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) struct intel_crtc *crtc; struct intel_power_domain_mask put_domains[I915_MAX_PIPES] = {}; struct ref_tracker *wakeref = NULL; + int power_async_delay; for_each_new_intel_crtc_in_state(state, crtc, new_crtc_state) intel_atomic_dsb_prepare(state, crtc); @@ -7536,9 +7558,14 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) /* Now enable the clocks, plane, pipe, and connectors that we set up. */ display->modeset.funcs->commit_modeset_enables(state); + intel_display_power_dc3co_compute(state); + /* FIXME probably need to sequence this properly */ intel_program_dpkgc_latency(state); + if (intel_display_power_dc3co_allowed(display)) + intel_cmtg_program(state); + intel_wait_for_vblank_workers(state); /* FIXME: We should call drm_atomic_helper_commit_hw_done() here @@ -7632,11 +7659,12 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state) */ intel_uncore_arm_unclaimed_mmio_detection(uncore); } - /* - * Delay re-enabling DC states by 17 ms to avoid the off->on->off - * toggling overhead at and above 60 FPS. - */ - intel_display_power_put_async_delay(display, POWER_DOMAIN_DC_OFF, wakeref, 17); + + power_async_delay = intel_display_power_select_target_dc_state(state); + + intel_display_power_put_async_delay(display, + POWER_DOMAIN_DC_OFF, wakeref, power_async_delay); + intel_display_rpm_put(display, state->wakeref); /* diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h index 1963dbc80221..57ea4f2edf2a 100644 --- a/drivers/gpu/drm/i915/display/intel_display.h +++ b/drivers/gpu/drm/i915/display/intel_display.h @@ -424,6 +424,10 @@ void intel_set_m_n(struct intel_display *display, const struct intel_link_m_n *m_n, intel_reg_t data_m_reg, intel_reg_t data_n_reg, intel_reg_t link_m_reg, intel_reg_t link_n_reg); +void intel_set_transcoder_timings(const struct intel_crtc_state *crtc_state, + enum transcoder transcoder); +void intel_set_transcoder_timings_lrr(const struct intel_crtc_state *crtc_state, + enum transcoder transcoder); void intel_get_m_n(struct intel_display *display, struct intel_link_m_n *m_n, intel_reg_t data_m_reg, intel_reg_t data_n_reg, @@ -474,6 +478,9 @@ int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state, const char *reason, u8 pipe_mask); int intel_modeset_all_pipes_late(struct intel_atomic_state *state, const char *reason); +int intel_modeset_commit_pipes_for_atomic_state(struct intel_atomic_state *state, + u8 pipe_mask, + struct drm_modeset_acquire_ctx *ctx); int intel_modeset_commit_pipes(struct intel_display *display, u8 pipe_mask, struct drm_modeset_acquire_ctx *ctx); diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h index 09ce25a6d4b1..17f7d3abdb9c 100644 --- a/drivers/gpu/drm/i915/display/intel_display_core.h +++ b/drivers/gpu/drm/i915/display/intel_display_core.h @@ -325,14 +325,14 @@ struct intel_display { struct intel_bw_info { /* for each QGV point */ unsigned int deratedbw[I915_NUM_QGV_POINTS]; - /* for each PSF GV point */ - unsigned int psf_bw[I915_NUM_PSF_GV_POINTS]; - /* Peak BW for each QGV point */ - unsigned int peakbw[I915_NUM_QGV_POINTS]; - u8 num_qgv_points; - u8 num_psf_gv_points; u8 num_planes; } max[6]; + /* for each PSF GV point */ + unsigned int psf_bw[I915_NUM_PSF_GV_POINTS]; + /* Peak BW for each QGV point */ + unsigned int peakbw[I915_NUM_QGV_POINTS]; + u8 num_qgv_points; + u8 num_psf_gv_points; } bw; struct { @@ -538,6 +538,8 @@ struct intel_display { struct { struct i915_power_domains domains; + /* DC3CO state */ + struct intel_dc3co_state dc3co; /* Shadow for DISPLAY_PHY_CONTROL which can't be safely read */ u32 chv_phy_control; diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c index 08004c1ba03f..3f02868ef105 100644 --- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c +++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c @@ -32,6 +32,7 @@ #include "intel_display_types.h" #include "intel_dmc.h" #include "intel_dp.h" +#include "intel_dp_link_caps.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" #include "intel_dp_test.h" @@ -1342,6 +1343,7 @@ void intel_connector_debugfs_add(struct intel_connector *connector) intel_psr_connector_debugfs_add(connector); intel_alpm_lobf_debugfs_add(connector); intel_dp_link_training_debugfs_add(connector); + intel_dp_link_caps_debugfs_add(connector); intel_link_bw_connector_debugfs_add(connector); if (DISPLAY_VER(display) >= 11 && diff --git a/drivers/gpu/drm/i915/display/intel_display_device.c b/drivers/gpu/drm/i915/display/intel_display_device.c index 69a9f782935c..f17fc2c68472 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.c +++ b/drivers/gpu/drm/i915/display/intel_display_device.c @@ -101,6 +101,8 @@ static const struct intel_display_device_info no_display = {}; #define TRANSCODER_EDP_OFFSET 0x6f000 #define TRANSCODER_DSI0_OFFSET 0x6b000 #define TRANSCODER_DSI1_OFFSET 0x6b800 +#define TRANSCODER_CMTG0_OFFSET 0x6F000 +#define TRANSCODER_CMTG1_OFFSET 0x6F100 #define CURSOR_A_OFFSET 0x70080 #define CURSOR_B_OFFSET 0x700c0 @@ -1352,6 +1354,18 @@ static const struct intel_display_device_info xe2_lpd_display = { BIT(INTEL_FBC_A) | BIT(INTEL_FBC_B) | BIT(INTEL_FBC_C) | BIT(INTEL_FBC_D), .__runtime_defaults.has_dbuf_overlap_detection = true, + .trans_offsets = { + [TRANSCODER_A] = TRANSCODER_A_OFFSET, + [TRANSCODER_B] = TRANSCODER_B_OFFSET, + [TRANSCODER_C] = TRANSCODER_C_OFFSET, + [TRANSCODER_D] = TRANSCODER_D_OFFSET, + [TRANSCODER_CMTG0] = TRANSCODER_CMTG0_OFFSET, + [TRANSCODER_CMTG1] = TRANSCODER_CMTG1_OFFSET, + }, + .__runtime_defaults.cpu_transcoder_mask = + BIT(TRANSCODER_A) | BIT(TRANSCODER_B) | + BIT(TRANSCODER_C) | BIT(TRANSCODER_D) | + BIT(TRANSCODER_CMTG0) | BIT(TRANSCODER_CMTG1), }; static const struct intel_display_device_info wcl_display = { diff --git a/drivers/gpu/drm/i915/display/intel_display_device.h b/drivers/gpu/drm/i915/display/intel_display_device.h index 12e5a522a299..f77b3da2cff5 100644 --- a/drivers/gpu/drm/i915/display/intel_display_device.h +++ b/drivers/gpu/drm/i915/display/intel_display_device.h @@ -159,6 +159,7 @@ struct intel_display_platforms { #define HAS_CUR_FBC(__display) (!HAS_GMCH(__display) && IS_DISPLAY_VER(__display, 7, 13)) #define HAS_D12_PLANE_MINIMIZATION(__display) ((__display)->platform.rocketlake || (__display)->platform.alderlake_s) #define HAS_DBUF_OVERLAP_DETECTION(__display) (DISPLAY_RUNTIME_INFO(__display)->has_dbuf_overlap_detection) +#define HAS_DC3CO(__display) (DISPLAY_VER(__display) >= 35) #define HAS_DDI(__display) (DISPLAY_INFO(__display)->has_ddi) #define HAS_DISPLAY(__display) (DISPLAY_RUNTIME_INFO(__display)->pipe_mask != 0) #define HAS_DMC(__display) (DISPLAY_RUNTIME_INFO(__display)->has_dmc) @@ -292,7 +293,7 @@ struct intel_display_runtime_info { u32 rawclk_freq; u8 pipe_mask; - u8 cpu_transcoder_mask; + u16 cpu_transcoder_mask; u16 port_mask; u8 num_sprites[I915_MAX_PIPES]; diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index d0729936f681..bb5301b90231 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -43,6 +43,8 @@ #include "intel_dp_tunnel.h" #include "intel_dpll.h" #include "intel_dpll_mgr.h" +#include "intel_dram.h" +#include "intel_encoder.h" #include "intel_fb.h" #include "intel_fbc.h" #include "intel_fbdev.h" @@ -65,6 +67,8 @@ #include "intel_wm.h" #include "skl_watermark.h" +static int __intel_display_driver_pm_suspend(struct intel_display *display, bool shutdown); + bool intel_display_driver_probe_defer(struct pci_dev *pdev) { struct drm_privacy_screen *privacy_screen; @@ -200,11 +204,23 @@ int intel_display_driver_probe_noirq(struct intel_display *display) { int ret; + intel_opregion_setup(display); + + /* + * Fill the dram structure to get the system dram info. This will be + * used for memory latency calculation. + */ + ret = intel_dram_detect(display); + if (ret) + goto cleanup_opregion; + + intel_bw_init_hw(display); + if (HAS_DISPLAY(display)) { ret = drm_vblank_init(display->drm, INTEL_NUM_PIPES(display)); if (ret) - return ret; + goto cleanup_opregion; } intel_bios_init(display); @@ -303,6 +319,8 @@ int intel_display_driver_probe_noirq(struct intel_display *display) intel_display_power_driver_remove(display); cleanup_bios: intel_bios_driver_remove(display); +cleanup_opregion: + intel_opregion_cleanup(display); return ret; } @@ -604,6 +622,8 @@ void intel_display_driver_remove_noirq(struct intel_display *display) if (!HAS_DISPLAY(display)) return; + intel_hpd_cancel_work(display); + intel_display_driver_suspend_access(display); /* @@ -644,6 +664,8 @@ void intel_display_driver_remove_nogem(struct intel_display *display) intel_display_power_driver_remove(display); intel_bios_driver_remove(display); + + intel_opregion_cleanup(display); } void intel_display_driver_unregister(struct intel_display *display) @@ -674,34 +696,102 @@ void intel_display_driver_unregister(struct intel_display *display) intel_vga_unregister(display); } +void intel_display_driver_shutdown(struct intel_display *display) +{ + if (!HAS_DISPLAY(display)) + return; + + __intel_display_driver_pm_suspend(display, true); + + intel_encoder_shutdown_all(display); +} + +void intel_display_driver_shutdown_late(struct intel_display *display) +{ + if (!HAS_DISPLAY(display)) + return; + + /* + * The only requirement is to reboot with display DC states disabled, + * for now leaving all display power wells in the INIT power domain + * enabled. + */ + intel_display_power_driver_remove(display); +} + /* * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ -int intel_display_driver_suspend(struct intel_display *display) +static int __intel_display_driver_pm_suspend(struct intel_display *display, bool shutdown) { - struct drm_atomic_commit *state; - int ret; + int ret = 0; if (!HAS_DISPLAY(display)) return 0; - state = drm_atomic_helper_suspend(display->drm); - ret = PTR_ERR_OR_ZERO(state); - if (ret) - drm_err(display->drm, "Suspending crtc's failed with %i\n", - ret); - else - display->restore.modeset_state = state; + /* + * We do a lot of poking in a lot of registers, make sure they work + * properly. + */ + intel_display_power_disable(display); + + drm_client_dev_suspend(display->drm); + + drm_kms_helper_poll_disable(display->drm); + intel_display_driver_disable_user_access(display); + + if (shutdown) { + drm_atomic_helper_shutdown(display->drm); + } else { + struct drm_atomic_commit *state; + + state = drm_atomic_helper_suspend(display->drm); + ret = PTR_ERR_OR_ZERO(state); + if (ret) + drm_err(display->drm, "Suspending crtc's failed with %i\n", + ret); + else + display->restore.modeset_state = state; + } /* ensure all DPT VMAs have been unpinned for intel_dpt_suspend() */ flush_workqueue(display->wq.cleanup); intel_dp_mst_suspend(display); + intel_encoder_block_all_hpds(display); + + intel_hpd_cancel_work(display); + + intel_display_driver_suspend_access(display); + + intel_encoder_suspend_all(display); + return ret; } +int intel_display_driver_pm_suspend(struct intel_display *display) +{ + return __intel_display_driver_pm_suspend(display, false); +} + +void intel_display_driver_pm_suspend_late(struct intel_display *display, bool s2idle) +{ + if (!HAS_DISPLAY(display)) + return; + + intel_display_power_suspend_late(display, s2idle); +} + +void intel_display_driver_pm_resume_early(struct intel_display *display) +{ + if (!HAS_DISPLAY(display)) + return; + + intel_display_power_resume_early(display); +} + int __intel_display_driver_resume(struct intel_display *display, struct drm_atomic_commit *state, @@ -741,7 +831,7 @@ __intel_display_driver_resume(struct intel_display *display, return ret; } -void intel_display_driver_resume(struct intel_display *display) +void intel_display_driver_pm_resume(struct intel_display *display) { struct drm_atomic_commit *state = display->restore.modeset_state; struct drm_modeset_acquire_ctx ctx; @@ -750,6 +840,12 @@ void intel_display_driver_resume(struct intel_display *display) if (!HAS_DISPLAY(display)) return; + intel_display_driver_resume_access(display); + + intel_hpd_init(display); + + intel_encoder_unblock_all_hpds(display); + /* MST sideband requires HPD interrupts enabled */ intel_dp_mst_resume(display); @@ -779,4 +875,15 @@ void intel_display_driver_resume(struct intel_display *display) "Restoring old state failed with %i\n", ret); if (state) drm_atomic_commit_put(state); + + intel_display_driver_enable_user_access(display); + drm_kms_helper_poll_enable(display->drm); + + intel_hpd_poll_disable(display); + + intel_opregion_resume(display); + + drm_client_dev_resume(display->drm); + + intel_display_power_enable(display); } diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.h b/drivers/gpu/drm/i915/display/intel_display_driver.h index 5270c26a32e0..7eca3d17dd82 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.h +++ b/drivers/gpu/drm/i915/display/intel_display_driver.h @@ -24,8 +24,13 @@ void intel_display_driver_remove(struct intel_display *display); void intel_display_driver_remove_noirq(struct intel_display *display); void intel_display_driver_remove_nogem(struct intel_display *display); void intel_display_driver_unregister(struct intel_display *display); -int intel_display_driver_suspend(struct intel_display *display); -void intel_display_driver_resume(struct intel_display *display); +void intel_display_driver_shutdown(struct intel_display *display); +void intel_display_driver_shutdown_late(struct intel_display *display); + +int intel_display_driver_pm_suspend(struct intel_display *display); +void intel_display_driver_pm_suspend_late(struct intel_display *display, bool s2idle); +void intel_display_driver_pm_resume_early(struct intel_display *display); +void intel_display_driver_pm_resume(struct intel_display *display); /* interface for intel_display_reset.c */ int __intel_display_driver_resume(struct intel_display *display, diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.c b/drivers/gpu/drm/i915/display/intel_display_irq.c index 4a821b0674fd..bcb0ee22fb56 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.c +++ b/drivers/gpu/drm/i915/display/intel_display_irq.c @@ -1469,6 +1469,18 @@ static void gen8_de_irq_handler(struct intel_display *display, u32 master_ctl) found = true; } + if (DISPLAY_VER(display) == 35) { + if (iir & CMTG_VBLANK_A) { + intel_handle_vblank(display, PIPE_A); + found = true; + } + + if (iir & CMTG_VBLANK_B) { + intel_handle_vblank(display, PIPE_B); + found = true; + } + } + if (DISPLAY_VER(display) >= 11) { u32 te_trigger = iir & (DSI0_TE | DSI1_TE); @@ -2666,3 +2678,10 @@ void intel_display_irq_snapshot_print(const struct intel_display_irq_snapshot *s drm_printf(p, "DERRMR: 0x%08x\n", snapshot->derrmr); drm_printf(p, "ERR_INT: 0x%08x\n", snapshot->err_int); } + +void intel_display_irq_port_interrupt_mask(struct intel_display *display, u32 bits, bool mask) +{ + spin_lock_irq(&display->irq.lock); + bdw_update_port_irq(display, bits, mask ? 0 : bits); + spin_unlock_irq(&display->irq.lock); +} diff --git a/drivers/gpu/drm/i915/display/intel_display_irq.h b/drivers/gpu/drm/i915/display/intel_display_irq.h index a1227cee885a..84446bf53401 100644 --- a/drivers/gpu/drm/i915/display/intel_display_irq.h +++ b/drivers/gpu/drm/i915/display/intel_display_irq.h @@ -82,4 +82,6 @@ void i915gm_irq_cstate_wa(struct intel_display *display, bool enable); struct intel_display_irq_snapshot *intel_display_irq_snapshot_capture(struct intel_display *display); void intel_display_irq_snapshot_print(const struct intel_display_irq_snapshot *snapshot, struct drm_printer *p); +void intel_display_irq_port_interrupt_mask(struct intel_display *display, u32 bits, bool mask); + #endif /* __INTEL_DISPLAY_IRQ_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_display_limits.h b/drivers/gpu/drm/i915/display/intel_display_limits.h index 453f7b720815..ea89473c177f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_limits.h +++ b/drivers/gpu/drm/i915/display/intel_display_limits.h @@ -45,6 +45,8 @@ enum transcoder { TRANSCODER_DSI_1, TRANSCODER_DSI_A = TRANSCODER_DSI_0, /* legacy DSI */ TRANSCODER_DSI_C = TRANSCODER_DSI_1, /* legacy DSI */ + TRANSCODER_CMTG0, + TRANSCODER_CMTG1, I915_MAX_TRANSCODERS }; diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 2e51dfcd5dce..8e312f5b9f6d 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -14,7 +14,9 @@ #include "intel_cdclk.h" #include "intel_clock_gating.h" #include "intel_combo_phy.h" +#include "intel_crtc.h" #include "intel_de.h" +#include "intel_display.h" #include "intel_display_power.h" #include "intel_display_power_map.h" #include "intel_display_power_well.h" @@ -30,6 +32,8 @@ #include "intel_pch_refclk.h" #include "intel_pmdemand.h" #include "intel_pps_regs.h" +#include "intel_psr.h" +#include "intel_psr_regs.h" #include "intel_snps_phy.h" #include "skl_watermark.h" #include "skl_watermark_regs.h" @@ -267,7 +271,7 @@ sanitize_target_dc_state(struct intel_display *display, static const u32 states[] = { DC_STATE_EN_UPTO_DC6, DC_STATE_EN_UPTO_DC5, - DC_STATE_EN_DC3CO, + DC_STATE_EN_UPTO_DC3CO, DC_STATE_DISABLE, }; int i; @@ -285,6 +289,19 @@ sanitize_target_dc_state(struct intel_display *display, return target_dc_state; } +bool intel_display_power_get_and_reset_dc3co_to_dc6(struct intel_display *display) +{ + struct i915_power_domains *power_domains = &display->power.domains; + bool ret; + + mutex_lock(&power_domains->lock); + ret = power_domains->dc3co_to_dc6; + power_domains->dc3co_to_dc6 = false; + mutex_unlock(&power_domains->lock); + + return ret; +} + /** * intel_display_power_set_target_dc_state - Set target dc state. * @display: display device @@ -300,6 +317,7 @@ void intel_display_power_set_target_dc_state(struct intel_display *display, struct i915_power_well *power_well; bool dc_off_enabled; struct i915_power_domains *power_domains = &display->power.domains; + u32 old_target_dc_state; mutex_lock(&power_domains->lock); power_well = lookup_power_well(display, SKL_DISP_DC_OFF); @@ -320,8 +338,17 @@ void intel_display_power_set_target_dc_state(struct intel_display *display, if (!dc_off_enabled) intel_power_well_enable(display, power_well); + old_target_dc_state = power_domains->target_dc_state; power_domains->target_dc_state = state; + /* + * CMTG must be restored explicitly after DC6 exit. The dc3co_to_dc6 + * flag helps CMTG determine whether restoration is required. + */ + if (old_target_dc_state == DC_STATE_EN_UPTO_DC3CO && + power_domains->target_dc_state == DC_STATE_EN_UPTO_DC6) + power_domains->dc3co_to_dc6 = true; + if (!dc_off_enabled) intel_power_well_disable(display, power_well); @@ -358,6 +385,144 @@ u32 intel_display_power_get_current_dc_state(struct intel_display *display) return current_dc_state; } +bool intel_display_power_dc3co_supported(struct intel_display *display) +{ + struct i915_power_domains *power_domains = &display->power.domains; + + if (!HAS_DC3CO(display)) + return false; + + return (power_domains->allowed_dc_mask & DC_STATE_EN_UPTO_DC3CO) == DC_STATE_EN_UPTO_DC3CO; +} + +bool intel_display_power_dc3co_allowed(struct intel_display *display) +{ + struct intel_dc3co_state *dc3co = &display->power.dc3co; + bool allowed; + + if (!intel_display_power_dc3co_supported(display)) + return false; + + mutex_lock(&dc3co->lock); + allowed = dc3co->allowed; + mutex_unlock(&dc3co->lock); + + return allowed; +} + +void intel_display_power_dc3co_update(struct intel_display *display, u32 trigger) +{ + struct intel_dc3co_state *dc3co = &display->power.dc3co; + + if (!intel_display_power_dc3co_supported(display)) + return; + + mutex_lock(&dc3co->lock); + dc3co->trigger = trigger; + dc3co->allowed = !!trigger; + mutex_unlock(&dc3co->lock); +} + +static bool intel_dc3co_port_pipe_compatible(struct intel_dp *intel_dp, + const struct intel_crtc_state *crtc_state) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; + enum port port = dig_port->base.port; + int num_pipes = intel_crtc_num_joined_pipes(crtc_state); + + /* Need to follow 1:1 mapping because of CMTG restriction */ + if (DISPLAY_VER(to_intel_display(crtc_state)) == 35) + return num_pipes == 1 && + ((pipe == PIPE_A && port == PORT_A) || + (pipe == PIPE_B && port == PORT_B)); + else + return num_pipes == 1 && pipe <= PIPE_B && port <= PORT_B; +} + +void intel_display_power_dc3co_compute(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + struct intel_crtc *crtc; + struct intel_crtc_state *crtc_state; + struct intel_encoder *encoder; + struct intel_dp *intel_dp; + u8 active_pipes = 0; + enum pipe pipe; + u32 trigger = DC3CO_TRIGGER_NONE; + + if (!intel_display_power_dc3co_supported(display)) + return; + + for_each_intel_crtc(display, crtc) + active_pipes |= crtc->active ? BIT(crtc->pipe) : 0; + + active_pipes = intel_calc_active_pipes(state, active_pipes); + + if (hweight8(active_pipes) != 1) + goto done; + + pipe = ffs(active_pipes) - 1; + crtc = intel_crtc_for_pipe(display, pipe); + + crtc_state = to_intel_crtc_state(crtc->base.state); + + for_each_intel_encoder_mask(display->drm, encoder, + crtc_state->uapi.encoder_mask) { + if (encoder->type != INTEL_OUTPUT_EDP) + goto done; + + intel_dp = enc_to_intel_dp(encoder); + + if (!intel_dc3co_port_pipe_compatible(intel_dp, crtc_state)) + goto done; + + if (intel_psr2_in_deep_sleep(intel_dp)) + goto done; + } + + if (crtc_state->has_lobf) + trigger |= DC3CO_TRIGGER_LOBF; + if (crtc_state->has_panel_replay && intel_dp->as_sdp_supported) + trigger |= DC3CO_TRIGGER_PANEL_REPLAY; + if (crtc_state->has_sel_update) + trigger |= DC3CO_TRIGGER_PSR2; + +done: + intel_display_power_dc3co_update(display, trigger); +} + +/* + * Select the target DC state for this commit and return the async-put delay + * to use when releasing the DC_OFF reference. + * + * Picks DC_STATE_EN_UPTO_DC3CO when DC3CO can be enabled + * otherwise falls back to default DC state of DC_STATE_EN_UPTO_DC6. + * The chosen target is programmed via intel_display_power_set_target_dc_state(). + * + * Returns the async-put delay (in ms) to use when releasing the DC_OFF + * reference: DC3CO_PUT_ASYNC_DELAY_MS when DC3CO was selected, otherwise + * DC6_PUT_ASYNC_DELAY_MS. + */ +int intel_display_power_select_target_dc_state(struct intel_atomic_state *state) +{ + struct intel_display *display = to_intel_display(state); + u32 target_dc_state; + + if (!intel_display_power_dc3co_supported(display)) + return DC6_PUT_ASYNC_DELAY_MS; + + if (intel_display_power_dc3co_allowed(display)) + target_dc_state = DC_STATE_EN_UPTO_DC3CO; + else + target_dc_state = DC_STATE_EN_UPTO_DC6; + + intel_display_power_set_target_dc_state(display, target_dc_state); + + return target_dc_state == DC_STATE_EN_UPTO_DC3CO ? + DC3CO_PUT_ASYNC_DELAY_MS : DC6_PUT_ASYNC_DELAY_MS; +} + static void __async_put_domains_mask(struct i915_power_domains *power_domains, struct intel_power_domain_mask *mask) { @@ -956,7 +1121,9 @@ static u32 get_allowed_dc_mask(struct intel_display *display, int enable_dc) if (!HAS_DISPLAY(display)) return 0; - if (DISPLAY_VER(display) >= 20) + if (DISPLAY_VER(display) >= 35) + max_dc = 4; + else if (DISPLAY_VER(display) >= 20) max_dc = 2; else if (display->platform.dg2) max_dc = 1; @@ -999,10 +1166,10 @@ static u32 get_allowed_dc_mask(struct intel_display *display, int enable_dc) switch (requested_dc) { case 4: - mask |= DC_STATE_EN_DC3CO | DC_STATE_EN_UPTO_DC6; + mask |= DC_STATE_EN_UPTO_DC3CO | DC_STATE_EN_UPTO_DC6; break; case 3: - mask |= DC_STATE_EN_DC3CO | DC_STATE_EN_UPTO_DC5; + mask |= DC_STATE_EN_UPTO_DC3CO | DC_STATE_EN_UPTO_DC5; break; case 2: mask |= DC_STATE_EN_UPTO_DC6; @@ -1037,6 +1204,7 @@ int intel_display_power_init(struct intel_display *display) sanitize_target_dc_state(display, DC_STATE_EN_UPTO_DC6); mutex_init(&power_domains->lock); + mutex_init(&display->power.dc3co.lock); INIT_DELAYED_WORK(&power_domains->async_put_work, intel_display_power_put_async_work); @@ -1634,9 +1802,12 @@ static void tgl_bw_buddy_init(struct intel_display *display) if (table[config].page_mask == 0) { drm_dbg_kms(display->drm, "Unknown memory configuration; disabling address buddy logic.\n"); - for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) - intel_de_write(display, BW_BUDDY_CTL(i), - BW_BUDDY_DISABLE); + + if (DISPLAY_VER(display) < 20) { + for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) + intel_de_write(display, BW_BUDDY_CTL(i), + BW_BUDDY_DISABLE); + } } else { for_each_set_bit(i, &abox_mask, BITS_PER_TYPE(abox_mask)) { intel_de_write(display, BW_BUDDY_PAGE_MASK(i), diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h index 56dc89eed3f8..546af67b680b 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.h +++ b/drivers/gpu/drm/i915/display/intel_display_power.h @@ -9,9 +9,12 @@ #include #include +#include "intel_display_limits.h" + enum aux_ch; enum port; struct i915_power_well; +struct intel_atomic_state; struct intel_display; struct intel_encoder; struct ref_tracker; @@ -131,6 +134,36 @@ struct intel_power_domain_mask { DECLARE_BITMAP(bits, POWER_DOMAIN_NUM); }; +/* + * DC3CO enabling triggers (bitmask). + * DC3CO may be enabled when at least one of these triggers is active. + * Additional constraints may still apply. + */ +#define DC3CO_TRIGGER_NONE (0) +#define DC3CO_TRIGGER_PSR2 BIT(0) +#define DC3CO_TRIGGER_LOBF BIT(1) +#define DC3CO_TRIGGER_PANEL_REPLAY BIT(2) +#define DC3CO_TRIGGER_ALL (DC3CO_TRIGGER_PSR2 | \ + DC3CO_TRIGGER_LOBF | \ + DC3CO_TRIGGER_PANEL_REPLAY) + +/* + * Delay to re-enable DC5/DC6 states by 17 ms to avoid the off->on->off + * toggling overhead at and above 60 FPS. + */ +#define DC6_PUT_ASYNC_DELAY_MS 17 +/* + * Use minimal re-enable delay to allow DC3CO entry on + * the next idle frame. + */ +#define DC3CO_PUT_ASYNC_DELAY_MS 1 + +struct intel_dc3co_state { + struct mutex lock; /* protects allowed and trigger fields */ + bool allowed; /* DC3CO compute result */ + u32 trigger; /* Bitmask of active DC3CO triggers */ +}; + struct i915_power_domains { /* * Power wells needed for initialization at driver init and suspend @@ -138,6 +171,7 @@ struct i915_power_domains { */ bool initializing; bool display_core_suspended; + bool dc3co_to_dc6; int power_well_count; u32 dc_state; @@ -179,9 +213,15 @@ void intel_display_power_sanitize_state(struct intel_display *display); void intel_display_power_suspend_late(struct intel_display *display, bool s2idle); void intel_display_power_resume_early(struct intel_display *display); +bool intel_display_power_get_and_reset_dc3co_to_dc6(struct intel_display *display); void intel_display_power_set_target_dc_state(struct intel_display *display, u32 state); u32 intel_display_power_get_current_dc_state(struct intel_display *display); +bool intel_display_power_dc3co_supported(struct intel_display *display); +void intel_display_power_dc3co_update(struct intel_display *display, u32 trigger); +bool intel_display_power_dc3co_allowed(struct intel_display *display); +void intel_display_power_dc3co_compute(struct intel_atomic_state *state); +int intel_display_power_select_target_dc_state(struct intel_atomic_state *state); void intel_display_power_runtime_suspend(struct intel_display *display); void intel_display_power_runtime_resume(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.c b/drivers/gpu/drm/i915/display/intel_display_power_well.c index 04bd0dde5bed..02cb4d800e23 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.c +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.c @@ -726,12 +726,28 @@ static void assert_can_disable_dc9(struct intel_display *display) */ } +static u32 dc_state_ro_mask(struct intel_display *display) +{ + if (DISPLAY_VER(display) >= 20) + return DC_STATE_EN_CSR_MASK_CMTG_1 | DC_STATE_EN_CSR_MASK_CMTG_0; + else if (DISPLAY_VER(display) >= 13 && !display->platform.dg2) + return DC_STATE_EN_CSR_MASK_CMTG_0; + + return 0; +} + static void gen9_write_dc_state(struct intel_display *display, u32 state) { int rewrites = 0; int rereads = 0; u32 v; + /* + * Mask out RO status bits from read-back comparison. + * HW may set these bits independently, so exclude them + * to prevent the verify loop from retrying due to RO bits mismatch. + */ + u32 ro_mask = dc_state_ro_mask(display); intel_de_write(display, DC_STATE_EN, state); @@ -743,7 +759,7 @@ static void gen9_write_dc_state(struct intel_display *display, do { v = intel_de_read(display, DC_STATE_EN); - if (v != state) { + if ((v & ~ro_mask) != (state & ~ro_mask)) { intel_de_write(display, DC_STATE_EN, state); rewrites++; rereads = 0; @@ -753,10 +769,10 @@ static void gen9_write_dc_state(struct intel_display *display, } while (rewrites < 100); - if (v != state) + if ((v & ~ro_mask) != (state & ~ro_mask)) drm_err(display->drm, - "Writing dc state to 0x%x failed, now 0x%x\n", - state, v); + "Writing dc state to 0x%x failed, now 0x%x (ro_mask=0x%x)\n", + state, v, ro_mask); /* Most of the times we need one retry, avoid spam */ if (rewrites > 1) @@ -772,7 +788,7 @@ static u32 gen9_dc_mask(struct intel_display *display) mask = DC_STATE_EN_UPTO_DC5; if (DISPLAY_VER(display) >= 12) - mask |= DC_STATE_EN_DC3CO | DC_STATE_EN_UPTO_DC6 + mask |= DC_STATE_EN_UPTO_DC3CO | DC_STATE_EN_UPTO_DC6 | DC_STATE_EN_DC9; else if (DISPLAY_VER(display) == 11) mask |= DC_STATE_EN_UPTO_DC6 | DC_STATE_EN_DC9; @@ -866,21 +882,30 @@ void gen9_set_dc_state(struct intel_display *display, u32 state) power_domains->dc_state = val & mask; } -static void tgl_enable_dc3co(struct intel_display *display) +void xe3lpd_enable_dc_count(struct intel_display *display) { - drm_dbg_kms(display->drm, "Enabling DC3CO\n"); - gen9_set_dc_state(display, DC_STATE_EN_DC3CO); + if (DISPLAY_VER(display) < 35) + return; + + intel_de_write(display, DC_COUNT_EN, DC_COUNT_EN_COUNTER_ENABLE); } -static void tgl_disable_dc3co(struct intel_display *display) +static void assert_can_enable_dc3co(struct intel_display *display) { - drm_dbg_kms(display->drm, "Disabling DC3CO\n"); - intel_de_rmw(display, DC_STATE_EN, DC_STATE_DC3CO_STATUS, 0); - gen9_set_dc_state(display, DC_STATE_DISABLE); - /* - * Delay of 200us DC3CO Exit time B.Spec 49196 - */ - usleep_range(200, 210); + drm_WARN_ONCE(display->drm, + (intel_de_read(display, DC_STATE_EN) & + DC_STATE_EN_UPTO_DC3CO), + "DC3CO already programmed to be enabled.\n"); + + assert_main_dmc_loaded(display); +} + +static void xe3lpd_enable_dc3co(struct intel_display *display) +{ + assert_can_enable_dc3co(display); + drm_dbg_kms(display->drm, "Enabling DC3CO\n"); + intel_dmc_wl_enable(display, DC_STATE_EN_UPTO_DC3CO); + gen9_set_dc_state(display, DC_STATE_EN_UPTO_DC3CO); } static void assert_can_enable_dc5(struct intel_display *display) @@ -1039,8 +1064,8 @@ static void bxt_verify_dpio_phy_power_wells(struct intel_display *display) static bool gen9_dc_off_power_well_enabled(struct intel_display *display, struct i915_power_well *power_well) { - return ((intel_de_read(display, DC_STATE_EN) & DC_STATE_EN_DC3CO) == 0 && - (intel_de_read(display, DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0); + return ((intel_de_read(display, DC_STATE_EN) & DC_STATE_EN_UPTO_DC3CO) == 0 && + (intel_de_read(display, DC_STATE_EN) & DC_STATE_EN_UPTO_DC3CO_DC5_DC6_MASK) == 0); } static void gen9_assert_dbuf_enabled(struct intel_display *display) @@ -1061,11 +1086,6 @@ void gen9_disable_dc_states(struct intel_display *display) struct intel_cdclk_config cdclk_config = {}; u32 old_state = power_domains->dc_state; - if (power_domains->target_dc_state == DC_STATE_EN_DC3CO) { - tgl_disable_dc3co(display); - return; - } - if (HAS_DISPLAY(display)) { intel_dmc_wl_get_noreg(display); gen9_set_dc_state(display, DC_STATE_DISABLE); @@ -1076,9 +1096,13 @@ void gen9_disable_dc_states(struct intel_display *display) } if (old_state == DC_STATE_EN_UPTO_DC5 || - old_state == DC_STATE_EN_UPTO_DC6) + old_state == DC_STATE_EN_UPTO_DC6 || + old_state == DC_STATE_EN_UPTO_DC3CO) intel_dmc_wl_disable(display); + if (old_state == DC_STATE_EN_UPTO_DC3CO) + return; + intel_cdclk_get_cdclk(display, &cdclk_config); /* Can't read out voltage_level so can't use intel_cdclk_changed() */ drm_WARN_ON(display->drm, @@ -1114,8 +1138,8 @@ static void gen9_dc_off_power_well_disable(struct intel_display *display, return; switch (power_domains->target_dc_state) { - case DC_STATE_EN_DC3CO: - tgl_enable_dc3co(display); + case DC_STATE_EN_UPTO_DC3CO: + xe3lpd_enable_dc3co(display); break; case DC_STATE_EN_UPTO_DC6: skl_enable_dc6(display); diff --git a/drivers/gpu/drm/i915/display/intel_display_power_well.h b/drivers/gpu/drm/i915/display/intel_display_power_well.h index 8f5524da2d06..0ce64b894436 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power_well.h +++ b/drivers/gpu/drm/i915/display/intel_display_power_well.h @@ -159,6 +159,7 @@ void gen9_set_dc_state(struct intel_display *display, u32 state); void gen9_disable_dc_states(struct intel_display *display); void bxt_enable_dc9(struct intel_display *display); void bxt_disable_dc9(struct intel_display *display); +void xe3lpd_enable_dc_count(struct intel_display *display); extern const struct i915_power_well_ops i9xx_always_on_power_well_ops; extern const struct i915_power_well_ops chv_pipe_power_well_ops; diff --git a/drivers/gpu/drm/i915/display/intel_display_regs.h b/drivers/gpu/drm/i915/display/intel_display_regs.h index 4321f8b529da..39e50423132f 100644 --- a/drivers/gpu/drm/i915/display/intel_display_regs.h +++ b/drivers/gpu/drm/i915/display/intel_display_regs.h @@ -1458,6 +1458,8 @@ #define GEN9_AUX_CHANNEL_B (1 << 25) #define DSI1_TE (1 << 24) #define DSI0_TE (1 << 23) +#define CMTG_VBLANK_B (1 << 17) +#define CMTG_VBLANK_A (1 << 14) #define GEN8_DE_PORT_HOTPLUG(hpd_pin) REG_BIT(3 + _HPD_PIN_DDI(hpd_pin)) #define BXT_DE_PORT_HOTPLUG_MASK (GEN8_DE_PORT_HOTPLUG(HPD_PORT_A) | \ GEN8_DE_PORT_HOTPLUG(HPD_PORT_B) | \ @@ -2767,28 +2769,28 @@ enum skl_power_gate { */ /* CDCLK_CTL */ #define CDCLK_CTL _MMIO(0x46000) -#define CDCLK_FREQ_SEL_MASK REG_GENMASK(27, 26) +#define CDCLK_FREQ_SEL_MASK REG_GENMASK(27, 26) /* skl */ #define CDCLK_FREQ_450_432 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 0) -#define CDCLK_FREQ_540 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 1) +#define CDCLK_FREQ_540 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 1) #define CDCLK_FREQ_337_308 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 2) #define CDCLK_FREQ_675_617 REG_FIELD_PREP(CDCLK_FREQ_SEL_MASK, 3) -#define MDCLK_SOURCE_SEL_MASK REG_GENMASK(25, 25) +#define MDCLK_SOURCE_SEL_MASK REG_GENMASK(25, 25) /* lnl+ */ #define MDCLK_SOURCE_SEL_CD2XCLK REG_FIELD_PREP(MDCLK_SOURCE_SEL_MASK, 0) #define MDCLK_SOURCE_SEL_CDCLK_PLL REG_FIELD_PREP(MDCLK_SOURCE_SEL_MASK, 1) -#define BXT_CDCLK_CD2X_DIV_SEL_MASK REG_GENMASK(23, 22) +#define BXT_CDCLK_CD2X_DIV_SEL_MASK REG_GENMASK(23, 22) /* bxt+ */ #define BXT_CDCLK_CD2X_DIV_SEL_1 REG_FIELD_PREP(BXT_CDCLK_CD2X_DIV_SEL_MASK, 0) #define BXT_CDCLK_CD2X_DIV_SEL_1_5 REG_FIELD_PREP(BXT_CDCLK_CD2X_DIV_SEL_MASK, 1) #define BXT_CDCLK_CD2X_DIV_SEL_2 REG_FIELD_PREP(BXT_CDCLK_CD2X_DIV_SEL_MASK, 2) #define BXT_CDCLK_CD2X_DIV_SEL_4 REG_FIELD_PREP(BXT_CDCLK_CD2X_DIV_SEL_MASK, 3) -#define BXT_CDCLK_CD2X_PIPE(pipe) ((pipe) << 20) -#define CDCLK_DIVMUX_CD_OVERRIDE (1 << 19) -#define BXT_CDCLK_CD2X_PIPE_NONE BXT_CDCLK_CD2X_PIPE(3) -#define ICL_CDCLK_CD2X_PIPE(pipe) (_PICK(pipe, 0, 2, 6) << 19) -#define ICL_CDCLK_CD2X_PIPE_NONE (7 << 19) -#define TGL_CDCLK_CD2X_PIPE(pipe) BXT_CDCLK_CD2X_PIPE(pipe) -#define TGL_CDCLK_CD2X_PIPE_NONE ICL_CDCLK_CD2X_PIPE_NONE -#define BXT_CDCLK_SSA_PRECHARGE_ENABLE (1 << 16) -#define CDCLK_FREQ_DECIMAL_MASK (0x7ff) +#define BXT_CDCLK_CD2X_PIPE_MASK REG_GENMASK(21, 20) /* bxt/glk */ +#define BXT_CDCLK_CD2X_PIPE(pipe) REG_FIELD_PREP(BXT_CDCLK_CD2X_PIPE_MASK, (pipe)) +#define BXT_CDCLK_CD2X_PIPE_NONE REG_FIELD_PREP(BXT_CDCLK_CD2X_PIPE_MASK, 3) +#define ICL_CDCLK_CD2X_PIPE_MASK REG_GENMASK(21, 19) /* icl+ */ +#define ICL_CDCLK_CD2X_PIPE(pipe) REG_FIELD_PREP(ICL_CDCLK_CD2X_PIPE_MASK, (pipe) << 1) +#define ICL_CDCLK_CD2X_PIPE_NONE REG_FIELD_PREP(ICL_CDCLK_CD2X_PIPE_MASK, 7) +#define CDCLK_DIVMUX_CD_OVERRIDE REG_BIT(19) /* pre-icl */ +#define BXT_CDCLK_SSA_PRECHARGE_ENABLE REG_BIT(16) /* bxt/glk */ +#define CDCLK_FREQ_DECIMAL_MASK REG_GENMASK(10, 0) /* pre-lnl */ /* CDCLK_SQUASH_CTL */ #define CDCLK_SQUASH_CTL _MMIO(0x46008) @@ -3070,19 +3072,29 @@ enum skl_power_gate { /* GEN9 DC */ #define DC_STATE_EN _MMIO(0x45504) #define DC_STATE_DISABLE 0 -#define DC_STATE_EN_DC3CO REG_BIT(30) #define DC_STATE_DC3CO_STATUS REG_BIT(29) #define HOLD_PHY_CLKREQ_PG1_LATCH REG_BIT(21) #define HOLD_PHY_PG1_LATCH REG_BIT(20) -#define DC_STATE_EN_UPTO_DC5 (1 << 0) #define DC_STATE_EN_DC9 (1 << 3) -#define DC_STATE_EN_UPTO_DC6 (2 << 0) -#define DC_STATE_EN_UPTO_DC5_DC6_MASK 0x3 +#define DC_STATE_EN_UPTO_DC3CO_DC5_DC6_MASK REG_GENMASK(1, 0) +#define DC_STATE_EN_DISABLE REG_FIELD_PREP(DC_STATE_EN_UPTO_DC3CO_DC5_DC6_MASK, 0) +#define DC_STATE_EN_UPTO_DC5 REG_FIELD_PREP(DC_STATE_EN_UPTO_DC3CO_DC5_DC6_MASK, 1) +#define DC_STATE_EN_UPTO_DC6 REG_FIELD_PREP(DC_STATE_EN_UPTO_DC3CO_DC5_DC6_MASK, 2) +#define DC_STATE_EN_UPTO_DC3CO REG_FIELD_PREP(DC_STATE_EN_UPTO_DC3CO_DC5_DC6_MASK, 3) +/* display version 20+ */ +#define DC_STATE_EN_CSR_MASK_CMTG_1 REG_BIT(11) +/* display version 13+, except dg2 */ +#define DC_STATE_EN_CSR_MASK_CMTG_0 REG_BIT(10) #define DC_STATE_DEBUG _MMIO(0x45520) #define DC_STATE_DEBUG_MASK_CORES (1 << 0) #define DC_STATE_DEBUG_MASK_MEMORY_UP (1 << 1) +#define DC_COUNT_EN _MMIO(0x457B4) +#define DC_COUNT_EN_COUNTER_ENABLE REG_BIT(31) + +#define DC_STATE_DC3CO_RESIDENCY _MMIO(0x457B8) + #define D_COMP_BDW _MMIO(0x138144) /* Pipe WM_LINETIME - watermark line time */ diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index c21e0c0ef0b1..c048da7d6fea 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -58,6 +58,8 @@ struct cec_notifier; struct drm_printer; struct intel_connector; struct intel_ddi_buf_trans; +struct intel_dp_link_caps; +struct intel_dp_link_training; struct intel_fbc; struct intel_global_objs_state; struct intel_hdcp_shim; @@ -150,7 +152,6 @@ struct intel_framebuffer { unsigned int min_alignment; unsigned int vtd_guard; - unsigned int (*panic_tiling)(unsigned int x, unsigned int y, unsigned int width); struct intel_panic *panic; }; @@ -177,10 +178,12 @@ struct intel_encoder { enum intel_output_type (*compute_output_type)(struct intel_encoder *, struct intel_crtc_state *, struct drm_connector_state *); - int (*compute_config)(struct intel_encoder *, + int (*compute_config)(struct intel_atomic_state *, + struct intel_encoder *, struct intel_crtc_state *, struct drm_connector_state *); - int (*compute_config_late)(struct intel_encoder *, + int (*compute_config_late)(struct intel_atomic_state *, + struct intel_encoder *, struct intel_crtc_state *, struct drm_connector_state *); void (*pre_pll_enable)(struct intel_atomic_state *, @@ -1185,7 +1188,6 @@ struct intel_crtc_state { bool pkg_c_latency_used; /* Only used for state verification. */ enum intel_panel_replay_dsc_support panel_replay_dsc_support; - u32 dc3co_exitline; u16 su_y_granularity; u8 active_non_psr_pipes; u8 entry_setup_frames; @@ -1573,6 +1575,10 @@ struct intel_crtc { #endif bool vblank_psr_notify; + + struct { + bool enabled; + } cmtg; }; struct intel_plane_error { @@ -1772,14 +1778,16 @@ struct intel_psr { ktime_t last_exit; bool sink_not_reliable; bool irq_aux_error; + /* DC3CO allowed used to control PSR configuration */ + bool dc3co_allowed; + /* DC3CO disable work */ + struct delayed_work dc3co_work; u16 su_w_granularity; u16 su_y_granularity; bool source_panel_replay_support; bool sink_panel_replay_support; bool panel_replay_enabled; - u32 dc3co_exitline; u32 dc3co_exit_delay; - struct delayed_work dc3co_work; u8 entry_setup_frames; u8 io_wake_lines; @@ -1795,6 +1803,14 @@ struct intel_psr { struct ref_tracker *vblank_wakeref; }; +struct intel_dp_link_config { + int rate; + int lane_count; +}; + +#define INTEL_DP_LINK_CONFIG_NULL \ + ((struct intel_dp_link_config){}) + struct intel_dp { intel_reg_t output_reg; u32 DP; @@ -1820,29 +1836,9 @@ struct intel_dp { bool use_rate_select; /* Max sink lane count as reported by DP_MAX_LANE_COUNT */ int max_sink_lane_count; - /* intersection of source and sink rates */ - int num_common_rates; - int common_rates[DP_MAX_SUPPORTED_RATES]; - int max_common_lane_count; struct { /* TODO: move the rest of link specific fields to here */ bool active; - /* common rate,lane_count configs in bw order */ - int num_configs; -#define INTEL_DP_MAX_LANE_COUNT 4 -#define INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS (ilog2(INTEL_DP_MAX_LANE_COUNT) + 1) -#define INTEL_DP_LANE_COUNT_EXP_BITS order_base_2(INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS) -#define INTEL_DP_LINK_RATE_IDX_BITS (BITS_PER_TYPE(u8) - INTEL_DP_LANE_COUNT_EXP_BITS) -#define INTEL_DP_MAX_LINK_CONFIGS (DP_MAX_SUPPORTED_RATES * \ - INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS) - struct intel_dp_link_config { - u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS; - u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS; - } configs[INTEL_DP_MAX_LINK_CONFIGS]; - /* Max lane count for the current link */ - int max_lane_count; - /* Max rate for the current link */ - int max_rate; /* * Link parameters for which the MST topology was probed. * Tracking these ensures that the MST path resources are @@ -1851,13 +1847,8 @@ struct intel_dp { */ int mst_probed_lane_count; int mst_probed_rate; - int force_lane_count; - int force_rate; - bool retrain_disabled; - /* Sequential link training failures after a passing LT */ - int seq_train_failures; - int force_train_failure; - bool force_retrain; + struct intel_dp_link_training *training; + struct intel_dp_link_caps *caps; } link; bool reset_link_params; int mso_link_count; diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 481fb65b7110..11f5dbf91e68 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -941,6 +941,8 @@ void intel_dmc_load_program(struct intel_display *display) gen9_set_dc_state_debugmask(display); + xe3lpd_enable_dc_count(display); + pipedmc_clock_gating_wa(display, false); } @@ -1647,19 +1649,20 @@ static int intel_dmc_debugfs_status_show(struct seq_file *m, void *unused) DMC_VERSION_MINOR(dmc->version)); if (DISPLAY_VER(display) >= 12) { - intel_reg_t dc3co_reg; + if (DISPLAY_VER(display) >= 35) { + dc5_reg = DG1_DMC_DEBUG_DC5_COUNT; + seq_printf(m, "DC3CO count: %d\n", + intel_de_read(display, XE3P_DMC_DC3CO_COUNT)); - if (display->platform.dgfx || DISPLAY_VER(display) >= 14) { - dc3co_reg = DG1_DMC_DEBUG3; + seq_printf(m, "DC3CO residency: %d\n", + intel_de_read(display, DC_STATE_DC3CO_RESIDENCY)); + } else if (display->platform.dgfx || DISPLAY_VER(display) >= 14) { dc5_reg = DG1_DMC_DEBUG_DC5_COUNT; } else { - dc3co_reg = TGL_DMC_DEBUG3; dc5_reg = TGL_DMC_DEBUG_DC5_COUNT; dc6_reg = TGL_DMC_DEBUG_DC6_COUNT; } - seq_printf(m, "DC3CO count: %d\n", - intel_de_read(display, dc3co_reg)); } else { dc5_reg = display->platform.broxton ? BXT_DMC_DC3_DC5_COUNT : SKL_DMC_DC3_DC5_COUNT; diff --git a/drivers/gpu/drm/i915/display/intel_dmc_regs.h b/drivers/gpu/drm/i915/display/intel_dmc_regs.h index 38e342b45af0..6b7978fb8986 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_regs.h +++ b/drivers/gpu/drm/i915/display/intel_dmc_regs.h @@ -531,6 +531,8 @@ enum pipedmc_event_id { #define TGL_DMC_DEBUG3 _MMIO(0x101090) #define DG1_DMC_DEBUG3 _MMIO(0x13415c) +#define XE3P_DMC_DC3CO_COUNT _MMIO(0x8f05c) + #define DMC_WAKELOCK_CFG _MMIO(0x8F1B0) #define DMC_WAKELOCK_CFG_ENABLE REG_BIT(31) #define DMC_WAKELOCK1_CTL _MMIO(0x8F140) diff --git a/drivers/gpu/drm/i915/display/intel_dmc_wl.c b/drivers/gpu/drm/i915/display/intel_dmc_wl.c index b007343721e1..ab4e0e9573df 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc_wl.c +++ b/drivers/gpu/drm/i915/display/intel_dmc_wl.c @@ -267,7 +267,7 @@ static bool intel_dmc_wl_check_range(struct intel_display *display, * the DMC and requires a DC exit for proper access. */ switch (dc_state) { - case DC_STATE_EN_DC3CO: + case DC_STATE_EN_UPTO_DC3CO: ranges = xe3lpd_dc3co_dmc_ranges; break; case DC_STATE_EN_UPTO_DC5: diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index c81fc00a334c..6e3fa6662cbe 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -71,6 +70,7 @@ #include "intel_dp.h" #include "intel_dp_aux.h" #include "intel_dp_hdcp.h" +#include "intel_dp_link_caps.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" #include "intel_dp_test.h" @@ -313,7 +313,7 @@ static void intel_dp_set_max_sink_lane_count(struct intel_dp *intel_dp) } /* Get length of rates array potentially limited by max_rate. */ -static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate) +int intel_dp_rate_limit_len(const int *rates, int len, int max_rate) { int i; @@ -326,31 +326,6 @@ static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate) return 0; } -/* Get length of common rates array potentially limited by max_rate. */ -static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp, - int max_rate) -{ - return intel_dp_rate_limit_len(intel_dp->common_rates, - intel_dp->num_common_rates, max_rate); -} - -int intel_dp_common_rate(struct intel_dp *intel_dp, int index) -{ - struct intel_display *display = to_intel_display(intel_dp); - - if (drm_WARN_ON(display->drm, - index < 0 || index >= intel_dp->num_common_rates)) - return 162000; - - return intel_dp->common_rates[index]; -} - -/* Theoretical max between source and sink */ -int intel_dp_max_common_rate(struct intel_dp *intel_dp) -{ - return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1); -} - int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port) { int vbt_max_lanes = intel_bios_dp_max_lane_count(dig_port->base.devdata); @@ -364,43 +339,35 @@ int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port) /* * Theoretical max between source and sink. - * Return %true if the max common lane count changed. */ -static bool intel_dp_set_max_common_lane_count(struct intel_dp *intel_dp) +static int intel_dp_get_max_common_lane_count(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); int source_max = intel_dp_max_source_lane_count(dig_port); int sink_max = intel_dp->max_sink_lane_count; int lane_max = intel_tc_port_max_lane_count(dig_port); int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps); - int old_max_common_lane_count = intel_dp->max_common_lane_count; if (lttpr_max) sink_max = min(sink_max, lttpr_max); - intel_dp->max_common_lane_count = min3(source_max, sink_max, lane_max); - - return intel_dp->max_common_lane_count != old_max_common_lane_count; -} - -int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) -{ - return intel_dp->max_common_lane_count; -} - -static int forced_lane_count(struct intel_dp *intel_dp) -{ - return clamp(intel_dp->link.force_lane_count, 1, intel_dp_max_common_lane_count(intel_dp)); + return min3(source_max, sink_max, lane_max); } int intel_dp_max_lane_count(struct intel_dp *intel_dp) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + struct intel_dp_link_config max_link_limits; + struct intel_dp_link_config forced_params; int lane_count; - if (intel_dp->link.force_lane_count) - lane_count = forced_lane_count(intel_dp); + intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits); + intel_dp_link_caps_get_forced_params(link_caps, &forced_params); + + if (forced_params.lane_count) + lane_count = forced_params.lane_count; else - lane_count = intel_dp->link.max_lane_count; + lane_count = max_link_limits.lane_count; switch (lane_count) { case 1: @@ -415,8 +382,12 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp) static int intel_dp_min_lane_count(struct intel_dp *intel_dp) { - if (intel_dp->link.force_lane_count) - return forced_lane_count(intel_dp); + struct intel_dp_link_config forced_params; + + intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params); + + if (forced_params.lane_count) + return forced_params.lane_count; return 1; } @@ -698,174 +669,44 @@ int intel_dp_rate_index(const int *rates, int len, int rate) return -1; } -static int intel_dp_link_config_rate(struct intel_dp *intel_dp, - const struct intel_dp_link_config *lc) -{ - return intel_dp_common_rate(intel_dp, lc->link_rate_idx); -} - -static int intel_dp_link_config_lane_count(const struct intel_dp_link_config *lc) -{ - return 1 << lc->lane_count_exp; -} - -static int intel_dp_link_config_bw(struct intel_dp *intel_dp, - const struct intel_dp_link_config *lc) -{ - return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(intel_dp, lc), - intel_dp_link_config_lane_count(lc)); -} - -static int link_config_cmp_by_bw(const void *a, const void *b, const void *p) -{ - struct intel_dp *intel_dp = (struct intel_dp *)p; /* remove const */ - const struct intel_dp_link_config *lc_a = a; - const struct intel_dp_link_config *lc_b = b; - int bw_a = intel_dp_link_config_bw(intel_dp, lc_a); - int bw_b = intel_dp_link_config_bw(intel_dp, lc_b); - - if (bw_a != bw_b) - return bw_a - bw_b; - - return intel_dp_link_config_rate(intel_dp, lc_a) - - intel_dp_link_config_rate(intel_dp, lc_b); -} - -static void intel_dp_link_config_init(struct intel_dp *intel_dp) +static void intel_dp_get_common_rates(struct intel_dp *intel_dp, + int common_rates[DP_MAX_SUPPORTED_RATES], + int *num_common_rates) { struct intel_display *display = to_intel_display(intel_dp); - struct intel_dp_link_config *lc; - int num_common_lane_configs; - int i; - int j; - - if (drm_WARN_ON(display->drm, !is_power_of_2(intel_dp_max_common_lane_count(intel_dp)))) - return; - - num_common_lane_configs = ilog2(intel_dp_max_common_lane_count(intel_dp)) + 1; - - if (drm_WARN_ON(display->drm, intel_dp->num_common_rates * num_common_lane_configs > - ARRAY_SIZE(intel_dp->link.configs))) - return; - - intel_dp->link.num_configs = intel_dp->num_common_rates * num_common_lane_configs; - - lc = &intel_dp->link.configs[0]; - for (i = 0; i < intel_dp->num_common_rates; i++) { - for (j = 0; j < num_common_lane_configs; j++) { - lc->lane_count_exp = j; - lc->link_rate_idx = i; - - lc++; - } - } - - sort_r(intel_dp->link.configs, intel_dp->link.num_configs, - sizeof(intel_dp->link.configs[0]), - link_config_cmp_by_bw, NULL, - intel_dp); -} - -void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count) -{ - struct intel_display *display = to_intel_display(intel_dp); - const struct intel_dp_link_config *lc; - - if (drm_WARN_ON(display->drm, idx < 0 || idx >= intel_dp->link.num_configs)) - idx = 0; - - lc = &intel_dp->link.configs[idx]; - - *link_rate = intel_dp_link_config_rate(intel_dp, lc); - *lane_count = intel_dp_link_config_lane_count(lc); -} - -int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count) -{ - int link_rate_idx = intel_dp_rate_index(intel_dp->common_rates, intel_dp->num_common_rates, - link_rate); - int lane_count_exp = ilog2(lane_count); - int i; - - for (i = 0; i < intel_dp->link.num_configs; i++) { - const struct intel_dp_link_config *lc = &intel_dp->link.configs[i]; - - if (lc->lane_count_exp == lane_count_exp && - lc->link_rate_idx == link_rate_idx) - return i; - } - - return -1; -} - -/* Return %true if the common rates changed. */ -static bool intel_dp_set_common_rates(struct intel_dp *intel_dp) -{ - struct intel_display *display = to_intel_display(intel_dp); - int num_old_common_rates = intel_dp->num_common_rates; - int old_common_rates[DP_MAX_SUPPORTED_RATES]; drm_WARN_ON(display->drm, !intel_dp->num_source_rates || !intel_dp->num_sink_rates); - /* TODO: Add a struct containing both rates and number of rates. */ - static_assert(__same_type(old_common_rates[0], intel_dp->common_rates[0]) && - sizeof(old_common_rates) == sizeof(intel_dp->common_rates)); - memcpy(old_common_rates, intel_dp->common_rates, - num_old_common_rates * sizeof(old_common_rates[0])); - - intel_dp->num_common_rates = intersect_rates(intel_dp->source_rates, - intel_dp->num_source_rates, - intel_dp->sink_rates, - intel_dp->num_sink_rates, - intel_dp->common_rates); + *num_common_rates = intersect_rates(intel_dp->source_rates, + intel_dp->num_source_rates, + intel_dp->sink_rates, + intel_dp->num_sink_rates, + common_rates); /* Paranoia, there should always be something in common. */ - if (drm_WARN_ON(display->drm, intel_dp->num_common_rates == 0)) { - intel_dp->common_rates[0] = 162000; - intel_dp->num_common_rates = 1; + if (drm_WARN_ON(display->drm, *num_common_rates == 0)) { + common_rates[0] = 162000; + *num_common_rates = 1; } - - return num_old_common_rates != intel_dp->num_common_rates || - memcmp(old_common_rates, intel_dp->common_rates, - num_old_common_rates * sizeof(old_common_rates[0])); } /* Return %true if any common link param changed. */ static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp) { + int num_common_rates; + int common_rates[DP_MAX_SUPPORTED_RATES]; bool params_changed = false; - if (intel_dp_set_common_rates(intel_dp)) + intel_dp_get_common_rates(intel_dp, common_rates, &num_common_rates); + if (intel_dp_link_caps_update(intel_dp->link.caps, + common_rates, num_common_rates, + intel_dp_get_max_common_lane_count(intel_dp))) params_changed = true; - if (intel_dp_set_max_common_lane_count(intel_dp)) - params_changed = true; - - intel_dp_link_config_init(intel_dp); - return params_changed; } -bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate, - u8 lane_count) -{ - /* - * FIXME: we need to synchronize the current link parameters with - * hardware readout. Currently fast link training doesn't work on - * boot-up. - */ - if (link_rate == 0 || - link_rate > intel_dp->link.max_rate) - return false; - - if (lane_count == 0 || - lane_count > intel_dp_max_lane_count(intel_dp)) - return false; - - return true; -} - u32 intel_dp_mode_to_fec_clock(u32 mode_clock) { return div_u64(mul_u32_u32(mode_clock, DP_DSC_FEC_OVERHEAD_FACTOR), @@ -1693,41 +1534,40 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp) seq_buf_print_array(&s, intel_dp->sink_rates, intel_dp->num_sink_rates); drm_dbg_kms(display->drm, "sink rates: %s\n", seq_buf_str(&s)); - seq_buf_clear(&s); - seq_buf_print_array(&s, intel_dp->common_rates, intel_dp->num_common_rates); - drm_dbg_kms(display->drm, "common rates: %s\n", seq_buf_str(&s)); -} - -static int forced_link_rate(struct intel_dp *intel_dp) -{ - int len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.force_rate); - - if (len == 0) - return intel_dp_common_rate(intel_dp, 0); - - return intel_dp_common_rate(intel_dp, len - 1); + intel_dp_link_caps_print_common_rates(intel_dp->link.caps); } int intel_dp_max_link_rate(struct intel_dp *intel_dp) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + struct intel_dp_link_config max_link_limits; + struct intel_dp_link_config forced_params; int len; - if (intel_dp->link.force_rate) - return forced_link_rate(intel_dp); + intel_dp_link_caps_get_forced_params(link_caps, &forced_params); - len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate); + if (forced_params.rate) + return forced_params.rate; - return intel_dp_common_rate(intel_dp, len - 1); + intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits); + len = intel_dp_common_len_rate_limit(link_caps, max_link_limits.rate); + + return intel_dp_common_rate(link_caps, len - 1); } static int intel_dp_min_link_rate(struct intel_dp *intel_dp) { - if (intel_dp->link.force_rate) - return forced_link_rate(intel_dp); + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + struct intel_dp_link_config forced_params; - return intel_dp_common_rate(intel_dp, 0); + intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params); + + if (forced_params.rate) + return forced_params.rate; + + return intel_dp_common_rate(link_caps, 0); } int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) @@ -1911,6 +1751,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, const struct drm_connector_state *conn_state, const struct link_config_limits *limits) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state); int link_rate, link_avail; @@ -1920,8 +1761,8 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp, int link_bpp_x16 = intel_dp_output_format_link_bpp_x16(pipe_config->output_format, bpp); - for (i = 0; i < intel_dp->num_common_rates; i++) { - link_rate = intel_dp_common_rate(intel_dp, i); + for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) { + link_rate = intel_dp_common_rate(link_caps, i); if (link_rate < limits->min_rate || link_rate > limits->max_rate) continue; @@ -2145,12 +1986,13 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp, const struct link_config_limits *limits, int dsc_bpp_x16) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; int link_rate, lane_count; int i; - for (i = 0; i < intel_dp->num_common_rates; i++) { - link_rate = intel_dp_common_rate(intel_dp, i); + for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) { + link_rate = intel_dp_common_rate(link_caps, i); if (link_rate < limits->min_rate || link_rate > limits->max_rate) continue; @@ -3685,19 +3527,19 @@ int intel_dp_compute_min_hblank(struct intel_crtc_state *crtc_state, } int -intel_dp_compute_config(struct intel_encoder *encoder, +intel_dp_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { struct intel_display *display = to_intel_display(encoder); - struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state); struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_connector *connector = intel_dp->attached_connector; int ret = 0, link_bpp_x16; if (intel_dp_is_edp(intel_dp)) { - ret = intel_panel_compute_config(connector, adjusted_mode); + ret = intel_panel_compute_config(state, pipe_config, connector); if (ret) return ret; } @@ -3810,12 +3652,10 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp, void intel_dp_reset_link_params(struct intel_dp *intel_dp) { - intel_dp->link.max_lane_count = intel_dp_max_common_lane_count(intel_dp); - intel_dp->link.max_rate = intel_dp_max_common_rate(intel_dp); + intel_dp_link_caps_reset(intel_dp->link.caps); intel_dp->link.mst_probed_lane_count = 0; intel_dp->link.mst_probed_rate = 0; - intel_dp->link.retrain_disabled = false; - intel_dp->link.seq_train_failures = 0; + intel_dp_link_training_reset(intel_dp->link.training); } /* Enable backlight PWM and backlight PP control. */ @@ -5715,32 +5555,6 @@ void intel_read_dp_sdp(struct intel_encoder *encoder, } } -static bool intel_dp_link_ok(struct intel_dp *intel_dp, - u8 link_status[DP_LINK_STATUS_SIZE]) -{ - struct intel_display *display = to_intel_display(intel_dp); - struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; - bool uhbr = intel_dp->link_rate >= 1000000; - bool ok; - - if (uhbr) - ok = drm_dp_128b132b_lane_channel_eq_done(link_status, - intel_dp->lane_count); - else - ok = drm_dp_channel_eq_ok(link_status, intel_dp->lane_count); - - if (ok) - return true; - - intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status); - drm_dbg_kms(display->drm, - "[ENCODER:%d:%s] %s link not ok, retraining\n", - encoder->base.base.id, encoder->base.name, - uhbr ? "128b/132b" : "8b/10b"); - - return false; -} - static void intel_dp_mst_hpd_irq(struct intel_dp *intel_dp, u8 *esi, u8 *ack) { @@ -5774,7 +5588,7 @@ static bool intel_dp_check_mst_status(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); - bool force_retrain = intel_dp->link.force_retrain; + bool force_retrain = intel_dp_link_training_get_force_retrain(intel_dp->link.training); bool reprobe_needed = false; for (;;) { @@ -5847,78 +5661,6 @@ intel_dp_handle_hdmi_link_status_change(struct intel_dp *intel_dp) } } -static int -intel_dp_read_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE]) -{ - int err; - - memset(link_status, 0, DP_LINK_STATUS_SIZE); - - if (intel_dp_mst_active_streams(intel_dp) > 0) - err = drm_dp_dpcd_read_data(&intel_dp->aux, DP_LANE0_1_STATUS_ESI, - link_status, DP_LINK_STATUS_SIZE - 2); - else - err = drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX, - link_status); - - if (err) - return err; - - if (link_status[DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS] & - DP_DOWNSTREAM_PORT_STATUS_CHANGED) - WRITE_ONCE(intel_dp->downstream_port_changed, true); - - return 0; -} - -static bool -intel_dp_needs_link_retrain(struct intel_dp *intel_dp) -{ - u8 link_status[DP_LINK_STATUS_SIZE]; - - if (!intel_dp->link.active) - return false; - - /* - * While PSR source HW is enabled, it will control main-link sending - * frames, enabling and disabling it so trying to do a retrain will fail - * as the link would or not be on or it could mix training patterns - * and frame data at the same time causing retrain to fail. - * Also when exiting PSR, HW will retrain the link anyways fixing - * any link status error. - */ - if (intel_psr_enabled(intel_dp)) - return false; - - if (intel_dp->link.force_retrain) - return true; - - if (intel_dp_read_link_status(intel_dp, link_status) < 0) - return false; - - /* - * Validate the cached values of intel_dp->link_rate and - * intel_dp->lane_count before attempting to retrain. - * - * FIXME would be nice to user the crtc state here, but since - * we need to call this from the short HPD handler that seems - * a bit hard. - */ - if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate, - intel_dp->lane_count)) - return false; - - if (intel_dp->link.retrain_disabled) - return false; - - if (intel_dp->link.seq_train_failures) - return true; - - /* Retrain if link not ok */ - return !intel_dp_link_ok(intel_dp, link_status) && - !intel_psr_link_ok(intel_dp); -} - bool intel_dp_has_connector(struct intel_dp *intel_dp, const struct drm_connector_state *conn_state) { @@ -6010,86 +5752,6 @@ void intel_dp_flush_connector_commits(struct intel_connector *connector) wait_for_connector_hw_done(connector->base.state); } -static bool intel_dp_is_connected(struct intel_dp *intel_dp) -{ - struct intel_connector *connector = intel_dp->attached_connector; - - return connector->base.status == connector_status_connected || - intel_dp->is_mst; -} - -static int intel_dp_retrain_link(struct intel_encoder *encoder, - struct drm_modeset_acquire_ctx *ctx) -{ - struct intel_display *display = to_intel_display(encoder); - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - u8 pipe_mask; - int ret; - - if (!intel_dp_is_connected(intel_dp)) - return 0; - - ret = drm_modeset_lock(&display->drm->mode_config.connection_mutex, - ctx); - if (ret) - return ret; - - if (!intel_dp_needs_link_retrain(intel_dp)) - return 0; - - ret = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask); - if (ret) - return ret; - - if (pipe_mask == 0) - return 0; - - if (!intel_dp_needs_link_retrain(intel_dp)) - return 0; - - drm_dbg_kms(display->drm, - "[ENCODER:%d:%s] retraining link (forced %s)\n", - encoder->base.base.id, encoder->base.name, - str_yes_no(intel_dp->link.force_retrain)); - - ret = intel_modeset_commit_pipes(display, pipe_mask, ctx); - if (ret == -EDEADLK) - return ret; - - intel_dp->link.force_retrain = false; - - if (ret) - drm_dbg_kms(display->drm, - "[ENCODER:%d:%s] link retraining failed: %pe\n", - encoder->base.base.id, encoder->base.name, - ERR_PTR(ret)); - - return ret; -} - -void intel_dp_link_check(struct intel_encoder *encoder) -{ - struct drm_modeset_acquire_ctx ctx; - int ret; - - intel_modeset_lock_ctx_retry(&ctx, NULL, 0, ret) - ret = intel_dp_retrain_link(encoder, &ctx); -} - -void intel_dp_check_link_state(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct intel_encoder *encoder = &dig_port->base; - - if (!intel_dp_is_connected(intel_dp)) - return; - - if (!intel_dp_needs_link_retrain(intel_dp)) - return; - - intel_encoder_link_check_queue_work(encoder, 0); -} - static void intel_dp_handle_device_service_irq(struct intel_dp *intel_dp, u8 irq_mask) { struct intel_display *display = to_intel_display(intel_dp); @@ -6185,7 +5847,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) /* * Force checking the link status for DPCD_REV < 1.2 * TODO: let the link status check depend on LINK_STATUS_CHANGED - * or intel_dp->link.force_retrain for DPCD_REV >= 1.2 + * or intel_dp->link.training.force_retrain for DPCD_REV >= 1.2 */ esi[3] |= LINK_STATUS_CHANGED; if (intel_dp_handle_link_service_irq(intel_dp, esi[3])) @@ -7688,3 +7350,25 @@ u8 intel_dp_as_sdp_transmission_time(void) return DP_PR_AS_SDP_SETUP_TIME_T1; } + +int intel_dp_link_init(struct intel_dp *intel_dp) +{ + intel_dp->link.training = intel_dp_link_training_init(intel_dp); + if (!intel_dp->link.training) + return -ENOMEM; + + intel_dp->link.caps = intel_dp_link_caps_init(intel_dp); + if (!intel_dp->link.caps) { + intel_dp_link_training_cleanup(intel_dp->link.training); + + return -ENOMEM; + } + + return 0; +} + +void intel_dp_link_cleanup(struct intel_dp *intel_dp) +{ + intel_dp_link_caps_cleanup(intel_dp->link.caps); + intel_dp_link_training_cleanup(intel_dp->link.training); +} diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h index 46a7f5c70981..02b691df6755 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.h +++ b/drivers/gpu/drm/i915/display/intel_dp.h @@ -59,8 +59,6 @@ int intel_dp_get_active_pipes(struct intel_dp *intel_dp, struct drm_modeset_acquire_ctx *ctx, u8 *pipe_mask); void intel_dp_flush_connector_commits(struct intel_connector *connector); -void intel_dp_link_check(struct intel_encoder *encoder); -void intel_dp_check_link_state(struct intel_dp *intel_dp); void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode); void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); @@ -73,7 +71,8 @@ void intel_dp_sink_disable_decompression(struct intel_atomic_state *state, void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); void intel_dp_encoder_shutdown(struct intel_encoder *intel_encoder); void intel_dp_encoder_flush_work(struct drm_encoder *encoder); -int intel_dp_compute_config(struct intel_encoder *encoder, +int intel_dp_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state); bool intel_dp_needs_8b10b_fec(const struct intel_crtc_state *crtc_state, @@ -102,17 +101,13 @@ void intel_edp_backlight_off(const struct drm_connector_state *conn_state); void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp); void intel_dp_mst_suspend(struct intel_display *display); void intel_dp_mst_resume(struct intel_display *display); +int intel_dp_rate_limit_len(const int *rates, int len, int max_rate); int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port); int intel_dp_max_link_rate(struct intel_dp *intel_dp); int intel_dp_max_lane_count(struct intel_dp *intel_dp); int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state); int intel_dp_rate_select(struct intel_dp *intel_dp, int rate); -int intel_dp_max_common_rate(struct intel_dp *intel_dp); -int intel_dp_max_common_lane_count(struct intel_dp *intel_dp); -int intel_dp_common_rate(struct intel_dp *intel_dp, int index); int intel_dp_rate_index(const int *rates, int len, int rate); -int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count); -void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count); void intel_dp_update_sink_caps(struct intel_dp *intel_dp); void intel_dp_reset_link_params(struct intel_dp *intel_dp); @@ -209,8 +204,6 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev, struct intel_connector *connector); bool intel_dp_has_gamut_metadata_dip(struct intel_encoder *encoder); -bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate, - u8 lane_count); bool intel_dp_has_connector(struct intel_dp *intel_dp, const struct drm_connector_state *conn_state); int intel_dp_dsc_max_src_input_bpc(struct intel_display *display); @@ -243,4 +236,7 @@ bool intel_dp_joiner_candidate_valid(struct intel_connector *connector, u8 intel_dp_as_sdp_transmission_time(void); +int intel_dp_link_init(struct intel_dp *intel_dp); +void intel_dp_link_cleanup(struct intel_dp *intel_dp); + #endif /* __INTEL_DP_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c new file mode 100644 index 000000000000..1c34ba6c49c3 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c @@ -0,0 +1,675 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "intel_display_core.h" +#include "intel_display_types.h" +#include "intel_dp.h" +#include "intel_dp_link_caps.h" + +struct intel_dp_link_caps { + struct intel_dp *dp; + + /* Rate, lane count caps common to source and sink. */ + int num_rates; + int rates[DP_MAX_SUPPORTED_RATES]; + int max_lane_count; + + /* common rate,lane_count configs in bw order */ + int num_configs; +#define INTEL_DP_MAX_LANE_COUNT 4 +#define INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS (ilog2(INTEL_DP_MAX_LANE_COUNT) + 1) +#define INTEL_DP_LANE_COUNT_EXP_BITS order_base_2(INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS) +#define INTEL_DP_LINK_RATE_IDX_BITS (BITS_PER_TYPE(u8) - INTEL_DP_LANE_COUNT_EXP_BITS) +#define INTEL_DP_MAX_LINK_CONFIGS (DP_MAX_SUPPORTED_RATES * \ + INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS) + struct intel_dp_link_config_entry { + /* index into rates[] */ + u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS; + u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS; + } configs[INTEL_DP_MAX_LINK_CONFIGS]; + + /* + * Forced parameters requested via debugfs. Remains set across sink + * disconnects. + */ + struct intel_dp_link_config forced_params; + + /* + * User set maximum limits. These limits constrain the currently + * allowed set of configurations and are not adjusted when sink + * capabilities change. + * + * max_limits.rate/lane_count may come from different allowed + * configurations, i.e. the (max_limits.rate, max_limits.lane_count) + * tuple itself may not be an allowed configuration. + */ + struct intel_dp_link_config max_limits; +}; + +/* Get length of common rates array potentially limited by max_rate. */ +int intel_dp_common_len_rate_limit(struct intel_dp_link_caps *link_caps, + int max_rate) +{ + return intel_dp_rate_limit_len(link_caps->rates, + link_caps->num_rates, max_rate); +} + +int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index) +{ + struct intel_display *display = to_intel_display(link_caps->dp); + + if (drm_WARN_ON(display->drm, + index < 0 || index >= link_caps->num_rates)) + return 162000; + + return link_caps->rates[index]; +} + +int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate) +{ + return intel_dp_rate_index(link_caps->rates, + link_caps->num_rates, + rate); +} + +/* Theoretical max between source and sink */ +int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps) +{ + return intel_dp_common_rate(link_caps, link_caps->num_rates - 1); +} + +int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps) +{ + return link_caps->num_rates; +} + +void intel_dp_link_caps_print_common_rates(struct intel_dp_link_caps *link_caps) +{ + struct intel_display *display = to_intel_display(link_caps->dp); + DECLARE_SEQ_BUF(s, 128); + int i; + + for (i = 0; i < link_caps->num_rates; i++) + seq_buf_printf(&s, "%s%d", i ? ", " : "", link_caps->rates[i]); + + drm_dbg_kms(display->drm, "common rates: %s\n", seq_buf_str(&s)); +} + +int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps) +{ + return link_caps->max_lane_count; +} + +static int forced_lane_count(struct intel_dp_link_caps *link_caps) +{ + if (!link_caps->forced_params.lane_count) + return 0; + + return clamp(link_caps->forced_params.lane_count, + 1, intel_dp_link_caps_max_common_lane_count(link_caps)); +} + +static int forced_link_rate(struct intel_dp_link_caps *link_caps) +{ + int len; + + if (!link_caps->forced_params.rate) + return 0; + + len = intel_dp_common_len_rate_limit(link_caps, link_caps->forced_params.rate); + if (len == 0) + return intel_dp_common_rate(link_caps, 0); + + return intel_dp_common_rate(link_caps, len - 1); +} + +void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps, + struct intel_dp_link_config *forced_params) +{ + forced_params->rate = forced_link_rate(link_caps); + forced_params->lane_count = forced_lane_count(link_caps); +} + +static int intel_dp_link_config_rate(struct intel_dp_link_caps *link_caps, + const struct intel_dp_link_config_entry *lce) +{ + return intel_dp_common_rate(link_caps, lce->link_rate_idx); +} + +static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lce) +{ + return 1 << lce->lane_count_exp; +} + +static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps, + const struct intel_dp_link_config *max_link_limits) +{ + link_caps->max_limits = *max_link_limits; +} + +static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps) +{ + struct intel_dp_link_config max_link_limits = { + .rate = intel_dp_max_common_rate(link_caps), + .lane_count = intel_dp_link_caps_max_common_lane_count(link_caps), + }; + + set_max_link_limits_no_update(link_caps, &max_link_limits); +} + +/** + * intel_dp_link_caps_get_max_limits - get the current maximum link limits + * @link_caps: link capabilities state + * @max_link_limits: returned maximum link limits + * + * Return the current maximum rate and lane count limits in + * @max_link_limits. + * + * These limits constrain the set of allowed configurations. + * + * The limits are set to the maximum common supported values after + * intel_dp_link_caps_reset() is called, and can later be modified by + * intel_dp_link_caps_set_max_limits(). The max rate and lane count + * parameters are independent limits, so the pair does not necessarily + * define a valid configuration. + * + * This function may be called without serializing against updates to + * @link_caps. However, without such serialization the returned value may be + * an out-of-sync (link rate, lane count) tuple, i.e. the parameters may + * belong to different update snapshots in time. + */ +void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps, + struct intel_dp_link_config *max_link_limits) +{ + *max_link_limits = link_caps->max_limits; +} + +/** + * intel_dp_link_caps_set_max_limits - set the current maximum link limits + * @link_caps: link capabilities state + * @max_link_limits: new maximum link limits + * + * Set the current maximum rate and lane count limits to @max_link_limits, + * constraining the set of allowed configurations. + * + * Unlike intel_dp_link_caps_get_max_limits(), the caller must serialize + * this call against concurrent queries and updates to @link_caps, in line + * with the rest of the API. + * + * Return: + * - %true if the @link_caps cached max limits value got updated with + * @max_link_limits. + * - %false if @max_link_limits is invalid. + */ +bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps, + const struct intel_dp_link_config *max_link_limits) +{ + set_max_link_limits_no_update(link_caps, max_link_limits); + + /* TODO: validate max_link_limits */ + return true; +} + +/** + * intel_dp_link_caps_reset_max_limits - reset the current maximum link limits + * @link_caps: link capabilities state + * + * Reset the current maximum link limits to the maximum supported common link + * rate and lane count. + */ +void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps) +{ + reset_max_link_limits_no_update(link_caps); +} + +static int intel_dp_link_config_bw(struct intel_dp_link_caps *link_caps, + const struct intel_dp_link_config_entry *lce) +{ + return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(link_caps, lce), + intel_dp_link_config_lane_count(lce)); +} + +static int link_config_cmp_by_bw(const void *a, const void *b, const void *p) +{ + struct intel_dp *intel_dp = (struct intel_dp *)p; /* remove const */ + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + + const struct intel_dp_link_config_entry *lce_a = a; + const struct intel_dp_link_config_entry *lce_b = b; + int bw_a = intel_dp_link_config_bw(link_caps, lce_a); + int bw_b = intel_dp_link_config_bw(link_caps, lce_b); + + if (bw_a != bw_b) + return bw_a - bw_b; + + return intel_dp_link_config_rate(link_caps, lce_a) - + intel_dp_link_config_rate(link_caps, lce_b); +} + +/* Return %true if the supported link parameters have changed. */ +bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps, + const int *rates, int num_rates, int max_lane_count) +{ + struct intel_dp *intel_dp = link_caps->dp; + struct intel_display *display = to_intel_display(intel_dp); + struct intel_dp_link_config_entry *lce; + bool link_params_changed = false; + int num_common_lane_configs; + int i; + int j; + + if (drm_WARN_ON(display->drm, !is_power_of_2(max_lane_count))) + return false; + + if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(link_caps->rates))) + return false; + + num_common_lane_configs = ilog2(max_lane_count) + 1; + + if (drm_WARN_ON(display->drm, num_rates * num_common_lane_configs > + ARRAY_SIZE(link_caps->configs))) + return false; + + /* TODO: Add a struct containing both rates and number of rates. */ + static_assert(__same_type(rates[0], link_caps->rates[0])); + if (num_rates != link_caps->num_rates || + memcmp(rates, link_caps->rates, num_rates * sizeof(rates[0]))) + link_params_changed = true; + + if (max_lane_count != link_caps->max_lane_count) + link_params_changed = true; + + memcpy(link_caps->rates, rates, num_rates * sizeof(rates[0])); + link_caps->num_rates = num_rates; + link_caps->max_lane_count = max_lane_count; + + link_caps->num_configs = num_rates * num_common_lane_configs; + + lce = &link_caps->configs[0]; + for (i = 0; i < link_caps->num_rates; i++) { + for (j = 0; j < num_common_lane_configs; j++) { + lce->lane_count_exp = j; + lce->link_rate_idx = i; + + lce++; + } + } + + sort_r(link_caps->configs, link_caps->num_configs, + sizeof(link_caps->configs[0]), + link_config_cmp_by_bw, NULL, + intel_dp); + + return link_params_changed; +} + +void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps, + int idx, int *link_rate, int *lane_count) +{ + struct intel_display *display = to_intel_display(link_caps->dp); + const struct intel_dp_link_config_entry *lce; + + if (drm_WARN_ON(display->drm, idx < 0 || idx >= link_caps->num_configs)) + idx = 0; + + lce = &link_caps->configs[idx]; + + *link_rate = intel_dp_link_config_rate(link_caps, lce); + *lane_count = intel_dp_link_config_lane_count(lce); +} + +int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps, + int link_rate, int lane_count) +{ + int link_rate_idx = intel_dp_rate_index(link_caps->rates, link_caps->num_rates, + link_rate); + int lane_count_exp = ilog2(lane_count); + int i; + + for (i = 0; i < link_caps->num_configs; i++) { + const struct intel_dp_link_config_entry *lce = &link_caps->configs[i]; + + if (lce->lane_count_exp == lane_count_exp && + lce->link_rate_idx == link_rate_idx) + return i; + } + + return -1; +} + +/** + * intel_dp_link_caps_reset - reset link capability restrictions + * @link_caps: link capabilities state + * + * Reset all current restrictions except for the user requested forced + * parameters, thus updating the set of allowed configurations and the + * derived maximum link information accordingly. + * + * This function is regularly called after a sink is connected, either + * for the first time to the connector or after a previous sink was + * disconnected from it, and intel_dp_link_caps_update() was called. + */ +void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps) +{ + /* TODO: Update the maximum link information. */ + reset_max_link_limits_no_update(link_caps); +} + +static int i915_dp_force_link_rate_show(struct seq_file *m, void *data) +{ + struct intel_connector *connector = to_intel_connector(m->private); + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + int current_rate = -1; + int force_rate; + int err; + int i; + + err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (err) + return err; + + intel_dp_flush_connector_commits(connector); + + if (intel_dp->link.active) + current_rate = intel_dp->link_rate; + + force_rate = link_caps->forced_params.rate; + + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + seq_printf(m, "%sauto%s", + force_rate == 0 ? "[" : "", + force_rate == 0 ? "]" : ""); + + for (i = 0; i < intel_dp->num_source_rates; i++) + seq_printf(m, " %s%d%s%s", + intel_dp->source_rates[i] == force_rate ? "[" : "", + intel_dp->source_rates[i], + intel_dp->source_rates[i] == current_rate ? "*" : "", + intel_dp->source_rates[i] == force_rate ? "]" : ""); + + seq_putc(m, '\n'); + + return 0; +} + +static int parse_link_rate(struct intel_dp_link_caps *link_caps, const char __user *ubuf, size_t len) +{ + struct intel_dp *intel_dp = link_caps->dp; + char *kbuf; + const char *p; + int rate; + int ret = 0; + + kbuf = memdup_user_nul(ubuf, len); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + p = strim(kbuf); + + if (!strcmp(p, "auto")) { + rate = 0; + } else { + ret = kstrtoint(p, 0, &rate); + if (ret < 0) + goto out_free; + + if (intel_dp_rate_index(intel_dp->source_rates, + intel_dp->num_source_rates, + rate) < 0) + ret = -EINVAL; + } + +out_free: + kfree(kbuf); + + return ret < 0 ? ret : rate; +} + +static ssize_t i915_dp_force_link_rate_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct intel_connector *connector = to_intel_connector(m->private); + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + int rate; + int err; + + rate = parse_link_rate(link_caps, ubuf, len); + if (rate < 0) + return rate; + + err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (err) + return err; + + intel_dp_flush_connector_commits(connector); + + intel_dp_reset_link_params(intel_dp); + link_caps->forced_params.rate = rate; + + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + *offp += len; + + return len; +} +DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_link_rate); + +static int i915_dp_force_lane_count_show(struct seq_file *m, void *data) +{ + struct intel_connector *connector = to_intel_connector(m->private); + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + int current_lane_count = -1; + int force_lane_count; + int err; + int i; + + err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (err) + return err; + + intel_dp_flush_connector_commits(connector); + + if (intel_dp->link.active) + current_lane_count = intel_dp->lane_count; + force_lane_count = link_caps->forced_params.lane_count; + + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + seq_printf(m, "%sauto%s", + force_lane_count == 0 ? "[" : "", + force_lane_count == 0 ? "]" : ""); + + for (i = 1; i <= 4; i <<= 1) + seq_printf(m, " %s%d%s%s", + i == force_lane_count ? "[" : "", + i, + i == current_lane_count ? "*" : "", + i == force_lane_count ? "]" : ""); + + seq_putc(m, '\n'); + + return 0; +} + +static int parse_lane_count(const char __user *ubuf, size_t len) +{ + char *kbuf; + const char *p; + int lane_count; + int ret = 0; + + kbuf = memdup_user_nul(ubuf, len); + if (IS_ERR(kbuf)) + return PTR_ERR(kbuf); + + p = strim(kbuf); + + if (!strcmp(p, "auto")) { + lane_count = 0; + } else { + ret = kstrtoint(p, 0, &lane_count); + if (ret < 0) + goto out_free; + + switch (lane_count) { + case 1: + case 2: + case 4: + break; + default: + ret = -EINVAL; + } + } + +out_free: + kfree(kbuf); + + return ret < 0 ? ret : lane_count; +} + +static ssize_t i915_dp_force_lane_count_write(struct file *file, + const char __user *ubuf, + size_t len, loff_t *offp) +{ + struct seq_file *m = file->private_data; + struct intel_connector *connector = to_intel_connector(m->private); + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + int lane_count; + int err; + + lane_count = parse_lane_count(ubuf, len); + if (lane_count < 0) + return lane_count; + + err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (err) + return err; + + intel_dp_flush_connector_commits(connector); + + intel_dp_reset_link_params(intel_dp); + link_caps->forced_params.lane_count = lane_count; + + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + *offp += len; + + return len; +} +DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_lane_count); + +static int i915_dp_max_link_rate_show(void *data, u64 *val) +{ + struct intel_connector *connector = to_intel_connector(data); + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_config max_link_limits; + int err; + + err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (err) + return err; + + intel_dp_flush_connector_commits(connector); + + intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits); + *val = max_link_limits.rate; + + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_link_rate_fops, i915_dp_max_link_rate_show, NULL, "%llu\n"); + +static int i915_dp_max_lane_count_show(void *data, u64 *val) +{ + struct intel_connector *connector = to_intel_connector(data); + struct intel_display *display = to_intel_display(connector); + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_config max_link_limits; + int err; + + err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); + if (err) + return err; + + intel_dp_flush_connector_commits(connector); + + intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits); + *val = max_link_limits.lane_count; + + drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_lane_count_fops, i915_dp_max_lane_count_show, NULL, "%llu\n"); + + +/** + * intel_dp_link_caps_debugfs_add - add link caps debugfs files for a connector + * @connector: connector to add the debugfs files for + * + * Add the link-capability debugfs files for a DP @connector. + */ +void intel_dp_link_caps_debugfs_add(struct intel_connector *connector) +{ + struct dentry *root = connector->base.debugfs_entry; + + if (connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort && + connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) + return; + + debugfs_create_file("i915_dp_force_link_rate", 0644, root, + connector, &i915_dp_force_link_rate_fops); + + debugfs_create_file("i915_dp_force_lane_count", 0644, root, + connector, &i915_dp_force_lane_count_fops); + + debugfs_create_file("i915_dp_max_link_rate", 0444, root, + connector, &i915_dp_max_link_rate_fops); + + debugfs_create_file("i915_dp_max_lane_count", 0444, root, + connector, &i915_dp_max_lane_count_fops); +} + +struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp) +{ + struct intel_dp_link_caps *link_caps; + + link_caps = kzalloc_obj(*link_caps); + if (!link_caps) + return NULL; + + link_caps->dp = intel_dp; + + return link_caps; +} + +void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps) +{ + kfree(link_caps); +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h new file mode 100644 index 000000000000..af9028e7cb98 --- /dev/null +++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2026 Intel Corporation */ + +#ifndef __INTEL_DP_LINK_CAPS_H__ +#define __INTEL_DP_LINK_CAPS_H__ + +#include + +struct intel_connector; +struct intel_dp; +struct intel_dp_link_caps; +struct intel_dp_link_config; + +int intel_dp_common_len_rate_limit(struct intel_dp_link_caps *link_caps, + int max_rate); +int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index); +int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate); +int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps); +int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps); +int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps); + +void intel_dp_link_caps_print_common_rates(struct intel_dp_link_caps *link_caps); + +void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps, + struct intel_dp_link_config *forced_params); + +int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps, + int link_rate, int lane_count); +void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps, + int idx, int *link_rate, int *lane_count); + +void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps, + struct intel_dp_link_config *max_link_limits); +bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps, + const struct intel_dp_link_config *max_link_limits); +void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps); + +bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps, + const int *rates, int num_rates, int max_lane_count); +void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps); + +void intel_dp_link_caps_debugfs_add(struct intel_connector *connector); + +struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp); +void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps); + +#endif /* __INTEL_DP_LINK_CAPS_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index e566f2b49594..b521dd11b62a 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -27,18 +27,344 @@ #include #include +#include "intel_display.h" #include "intel_display_core.h" #include "intel_display_jiffies.h" #include "intel_display_types.h" #include "intel_display_utils.h" #include "intel_dp.h" +#include "intel_dp_link_caps.h" #include "intel_dp_link_training.h" +#include "intel_dp_mst.h" #include "intel_encoder.h" #include "intel_hdmi.h" #include "intel_hotplug.h" +#include "intel_modeset_lock.h" #include "intel_panel.h" #include "intel_psr.h" +/** + * DOC: DisplayPort link training + * + * This documents the Intel DisplayPort link training implementation and + * its internal interfaces, with a current focus on link recovery. + * + * Documentation of the full link training procedure is not yet included. + * + * The Intel DP link recovery logic governs how the driver reacts to + * link training failures and to links that degrade asynchronously + * after a previously successful training. Recovery is first attempted + * via automatic retraining (``autoretrain``) and, when that is no + * longer possible, by selecting fallback link configurations and + * notifying userspace to recover the link via a modeset. + * + * Recovery sequence and userspace notification + * -------------------------------------------- + * + * After the first link training failure following initialization or a + * previously successful training, recovery is first attempted by the + * driver via automatic retraining, without userspace involvement. + * During this phase, a given link configuration is attempted twice + * before being abandoned: after the initial link training failure, an + * automatic retraining modeset is performed with the same link + * parameters, constituting the second attempt. + * + * Once automatic retraining is no longer possible, recovery is delegated + * to userspace, which must select a new modeset configuration, as the + * kernel must not do so. From this point onwards, each link configuration + * may be attempted only once as userspace iterates through alternative + * configurations. A successful link training restores the automatic + * retraining model for subsequent failures. + * + * The failure of the last automatic retraining attempt is reported to + * userspace, and from that point onward the driver notifies userspace of + * each subsequent failure. This allows userspace to both initiate + * recovery via modesets and observe the outcome of those recovery + * attempts, even when no further fallback configurations remain. + * + * Link training failures are always reported to userspace, even when they + * result from a kernel-internal modeset. Such modesets only re-apply the + * existing userspace-provided state and must not modify it. A failure + * triggered by such a modeset is therefore treated the same as a link + * degradation after a previously successful training, and recovery is + * handled by userspace in place of the kernel caller. + * + * Contexts + * -------- + * + * The following execution contexts (A/B/C) describe how the different + * recovery states are reached but are not themselves implementation + * states. The actual state machine is defined by &enum + * intel_dp_link_training_recovery_state. + * + * A. Modeset context: + * + * Triggered by: + * - link training during a modeset, or + * - via the "i915_dp_force_link_training_failure" debugfs entry, + * forcing this path by emulating a link training failure. + * + * Transitions: + * - A1 Link training succeeds. + * + * A link check work to recover any degraded link is scheduled + * (and handled if needed in context B). + * + * State -> %INTEL_DP_LINK_RECOVERY_IDLE. + * + * - A2 First link training fails after initialization or a previously + * successful link training. + * + * An automatic retraining work is scheduled (and handled in + * context B) with the same link parameters with which the link + * training failed. + * + * State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING. + * + * - A3 Link training fails again after A2 or A3. + * + * Through fallback selection, the driver attempts to restrict the + * allowed link configurations for subsequent modesets. This may + * be done either by lowering global limits (rate/lane caps), or by + * disabling only the currently failing configuration while leaving + * all other configurations allowed, even if they use higher rate or + * lane count. + * + * (The current implementation may still apply parameter capping as + * a coarse fallback selection mechanism. This is transitional and is + * expected to be replaced by a scheme that disables only the failing + * configuration, rather than removing configurations that have not + * been observed to fail and may still train successfully.) + * + * This case may repeat in a loop: + * %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED -> + * %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED + * + * via repeated A3a -> A3a transitions until the configuration fallback + * space is exhausted, reaching the A3b terminal case. + * + * - A3a Fallback selection succeeds. + * + * Userspace is notified to retry the modeset. + * + * State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED. + * + * - A3b Fallback selection fails. + * + * Userspace is notified of the failure and may continue recovery + * by retrying the modeset with the remaining allowed link + * configuration. + * + * State -> %INTEL_DP_LINK_RECOVERY_NO_FALLBACK. + * + * B. Automatic retraining context: + * + * Triggered by: + * - after a successful link training in context A1 followed by + * asynchronous link degradation, or + * - after the first failed link training attempt in context A2, or + * - via the "i915_dp_force_link_retrain" debugfs entry, which may + * bypass normal gating and force this path. + * + * Transitions: + * - B1 ``Autoretrain`` modeset check and link training succeeds. + * + * The case is handled as in A1, scheduling a link check work to + * recover any degraded link. + * + * State -> %INTEL_DP_LINK_RECOVERY_IDLE. + * + * - B2 ``Autoretrain`` modeset check succeeds but link training fails. + * + * - B2a Previously the link degraded asynchronously (current state + * is %INTEL_DP_LINK_RECOVERY_IDLE). + * + * This corresponds to a first failure in a new failure + * sequence and is handled as in A2: an automatic retraining + * attempt is scheduled with the same link parameters. + * + * State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING. + * + * - B2b Previously a link training failed (current state is + * %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING). + * + * In non-regular (debug-forced) scenarios this may also be + * reached from + * %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED or + * %INTEL_DP_LINK_RECOVERY_NO_FALLBACK, effectively behaving + * like a userspace-driven recovery attempt. + * + * The failure is handled as in A3, performing a fallback selection: + * + * State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED (via A3a). + * + * or + * + * State -> %INTEL_DP_LINK_RECOVERY_NO_FALLBACK (via A3b). + * + * - B3 ``Autoretrain`` modeset check fails (and hence the link training + * cannot be started). + * + * The modeset check may fail, for example, due to external conditions + * such as changed shared link bandwidth, which can make previously + * valid modeset parameters no longer acceptable. + * + * In this case, automatic retraining is disabled without selecting + * a fallback configuration. The driver hands recovery over to + * userspace without modifying the allowed configuration set, so a + * subsequent userspace modeset will retry with the current link + * configuration. Userspace is in a better position to select new + * modeset parameters (e.g. video mode or enabled outputs) that + * satisfy the updated constraints, as the driver is only allowed + * to retry the modeset with the existing userspace-provided modeset + * configuration. + * + * This policy preserves the normal retry model, where a given link + * configuration is attempted twice in the automatic retraining + * flow before being abandoned: after a first link training failure, + * an automatic retraining modeset is performed with the same link + * parameters, and if its atomic check passes, the link training + * itself may either succeed or fail, constituting the second + * attempt. In this case, however, the retry modeset's atomic check + * failed, so no second link training attempt with those parameters + * was performed, and selecting a fallback would cause that + * configuration to be tried only once rather than twice. + * + * The userspace-driven link recovery continues with subsequent + * userspace modesets handled in A3. + * + * State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED. + * + * C. State reset context: + * + * Triggered by: + * - sink capability changes, or + * - sink disconnect/reconnect, or + * - system suspend/resume or power transitions where HPD + * handling may have been suppressed, or + * - successful link training. + * + * Transitions: + * - The recovery state is reset from any of the recovery states + * + * State -> %INTEL_DP_LINK_RECOVERY_IDLE. + * + * After reset, the driver may re-check link status and schedule + * retraining if the link is found to remain degraded. + * + * State transition summary + * ------------------------ + * + * - From %INTEL_DP_LINK_RECOVERY_IDLE + * + * - To %INTEL_DP_LINK_RECOVERY_IDLE + * + * - | In context: B1 + * | Action: no action + * + * - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING + * + * - | In contexts: A2, B2a + * | Action: queue ``autoretrain`` work + * + * - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED + * + * - | In context: B3 + * | Action: notify userspace + * + * - From %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING + * + * - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED + * + * - | In contexts: A3a, B2b + * | Action: select fallback configurations, notify userspace + * + * - | In context: B3 + * | Action: notify userspace + * + * - To %INTEL_DP_LINK_RECOVERY_NO_FALLBACK + * + * - | In contexts: A3b, B2b + * | Action: notify userspace + * + * - From %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED + * + * - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED + * + * - | In contexts: A3a, B2b + * | Action: select fallback configurations, notify userspace + * + * - To %INTEL_DP_LINK_RECOVERY_NO_FALLBACK + * + * - | In contexts: A3b, B2b + * | Action: notify userspace + * + * - From %INTEL_DP_LINK_RECOVERY_NO_FALLBACK + * + * - To %INTEL_DP_LINK_RECOVERY_NO_FALLBACK + * + * - | In contexts: A3b + * | Action: notify userspace + * + * - From any state + * + * - To %INTEL_DP_LINK_RECOVERY_IDLE + * + * - | In contexts: C + * | Action: no action + * + * Recovery flows + * -------------- + * + * Userspace modeset link recovery:: + * + * [IDLE] + * | + * | userspace modeset link training fails + * | (autoretrain link recovery work scheduled) + * v + * [AUTORETRAIN_PENDING]-- autoretrain link recovery succeeds -> [IDLE] + * | + * | autoretrain link recovery modeset check or link training fails + * | + * +--o--+ + * modeset check fails | | link training fails + * (userspace notified) | | + * | o-------- no fallback (userspace notified) ---> [NO_FALLBACK] + * | | + * +-------------+ | | fallback selected (userspace notified) + * | | | | + * | v v v + * | [AUTORETRAIN_DISABLED]--- userspace link recovery succeeds ----> [IDLE] + * | | + * | | userspace link recovery fails + * | | + * +-------------------o------------- no fallback (userspace notified) ----> [NO_FALLBACK] + * fallback selected + * (userspace notified) + * + * Asynchronous link degradation recovery:: + * + * [IDLE] + * | + * | link degrades + * | (autoretrain link recovery performed) + * | + * o--- autoretrain link recovery succeeds ---> [IDLE] + * | + * | autoretrain link recovery modeset check or link training fails + * | + * +--o--+ + * modeset check fails | | link training fails + * (userspace notified) | | (autoretrain work scheduled) + * v v + * [AUTORETRAIN_DISABLED*] [AUTORETRAIN_PENDING*] + * + * ``*`` marks states where the sequence continues from the corresponding state + * in the Userspace modeset link recovery flow above. + * + */ + #define LT_MSG_PREFIX "[CONNECTOR:%d:%s][ENCODER:%d:%s][%s] " #define LT_MSG_ARGS(_intel_dp, _dp_phy) (_intel_dp)->attached_connector->base.base.id, \ (_intel_dp)->attached_connector->base.name, \ @@ -60,7 +386,72 @@ lt_dbg(_intel_dp, _dp_phy, "Sink disconnected: " _format, ## __VA_ARGS__); \ } while (0) -#define MAX_SEQ_TRAIN_FAILURES 2 +/* + * enum intel_dp_link_recovery_state - LT recovery state + * @INTEL_DP_LINK_RECOVERY_IDLE: + * No link training failure is currently tracked and no recovery is + * in progress. This is the initial state after driver initialization, + * power state transitions, sink (re-)connection, or after a successful + * link training. + * + * @INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING: + * A first link training failure has been observed and an automatic + * retraining attempt with the same link parameters is pending. Exactly + * one such attempt is allowed before switching to userspace-driven + * recovery. + * + * @INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED: + * Automatic retraining is no longer possible. At this point, a + * fallback selection is made and userspace is notified to take over + * recovery, performing modesets with parameters it determines are + * required. The driver then selects a link configuration from the + * remaining fallback configuration set. Subsequent link training + * failures trigger further fallback selections and userspace + * notifications. + * + * @INTEL_DP_LINK_RECOVERY_NO_FALLBACK: + * Fallback selection is no longer possible, as no usable fallback link + * configurations remain. Recovery must proceed via userspace modesets + * using the remaining allowed link configuration. Userspace continues + * to be notified of subsequent link training failures. + * + * Describes the link recovery state used by the Intel DP link recovery + * logic. + * + * See also: + * - DOC: DisplayPort link training + * - link_recovery_autoretrain_pending() + * - link_recovery_autoretrain_allowed() + * - link_recovery_has_no_fallback() + * - link_recovery_mark_train_failure() + * - link_recovery_mark_autoretrain_modeset_failure() + * - link_recovery_mark_no_fallback() + * - link_recovery_reset() + */ +enum intel_dp_link_recovery_state { + /* + * Keep the enum values ordered from least to most severe + * recovery state; helper logic relies on that ordering. + */ + INTEL_DP_LINK_RECOVERY_IDLE, + INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING, + INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED, + INTEL_DP_LINK_RECOVERY_NO_FALLBACK, +}; + +struct intel_dp_link_training { + struct intel_dp *dp; + + enum intel_dp_link_recovery_state recovery_state; + + int force_train_failure; + bool force_retrain; +}; + +static struct intel_dp_link_training *connector_to_link_training(struct intel_connector *connector) +{ + return intel_attached_dp(connector)->link.training; +} static void intel_dp_reset_lttpr_common_caps(struct intel_dp *intel_dp) { @@ -245,12 +636,12 @@ int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_S * transparent mode link training mode. * * Returns: - * >0 if LTTPRs were detected and the non-transparent LT mode was set. The + * - >0 if LTTPRs were detected and the non-transparent LT mode was + * set. The DPRX capabilities are read out. + * - 0 if no LTTPRs or more than 8 LTTPRs were detected or in case of + * a detection failure and the transparent LT mode was set. The * DPRX capabilities are read out. - * 0 if no LTTPRs or more than 8 LTTPRs were detected or in case of a - * detection failure and the transparent LT mode was set. The DPRX - * capabilities are read out. - * <0 Reading out the DPRX capabilities failed. + * - <0 Reading out the DPRX capabilities failed. */ int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp) { @@ -1247,6 +1638,124 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp, return sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION ? 1 : 0; } +static bool +link_recovery_autoretrain_pending(struct intel_dp_link_training *link_training) +{ + return link_training->recovery_state == INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING; +} + +/* + * Automatic retraining is a driver-driven link recovery mechanism that + * retrains the link with the current userspace provided modeset + * configuration and link parameters. + * + * Autoretrain is allowed while the link configurations available for + * retraining, i.e. those not disabled yet via fallback selection, still + * make it possible to retrain the link for the current userspace provided + * modeset configuration. + * + * Once automatic retraining is no longer allowed, userspace driven link + * recovery via userspace notifications and userspace modesets takes over. + * + * See also: + * - DOC: DisplayPort link training + */ +static bool +link_recovery_autoretrain_allowed(struct intel_dp_link_training *link_training) +{ + switch (link_training->recovery_state) { + case INTEL_DP_LINK_RECOVERY_IDLE: + case INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING: + return true; + default: + return false; + } +} + +static bool +link_recovery_has_no_fallback(struct intel_dp_link_training *link_training) +{ + return link_training->recovery_state == INTEL_DP_LINK_RECOVERY_NO_FALLBACK; +} + +/* + * Record a link training failure and advance the recovery state to + * indicate the next required recovery step. + * + * The caller must proceed with recovery as instructed by the return + * value, either via automatic retraining or, once automatic retraining + * is no longer possible, via userspace modesets after fallback + * selection. + * + * Note that the error reported via this function is the error seen by + * the link training failure handler proper after an actual link + * training failure indicated by the sink device, and so the error and + * corresponding actions required are distinct from an autoretrain + * modeset failure. See link_recovery_mark_autoretrain_modeset_failure() to + * report a modeset failure. + * + * See also: + * - DOC: DisplayPort link training + */ +static bool +link_recovery_mark_train_failure(struct intel_dp_link_training *link_training) +{ + switch (link_training->recovery_state) { + case INTEL_DP_LINK_RECOVERY_IDLE: + link_training->recovery_state = INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING; + break; + case INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING: + link_training->recovery_state = INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED; + break; + default: + break; + } + + return link_recovery_autoretrain_allowed(link_training); +} + +/* + * Record a failure of the autoretrain modeset before link training + * itself could run. + * + * Note that the error reported via this function and the corresponding + * expected actions are distinct from an actual link training failure: + * the modeset failed before a link training attempt could be performed. + * See link_recovery_mark_train_failure() to report an actual link + * training failure. + * + * Update the state to indicate that further recovery is to be delegated to + * userspace via a regular modeset. + * + * See also: + * - DOC: DisplayPort link training + */ +static void +link_recovery_mark_autoretrain_modeset_failure(struct intel_dp_link_training *link_training) +{ + if (link_recovery_autoretrain_allowed(link_training)) + link_training->recovery_state = INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED; +} + +/* Record that no more link fallback configuration is available. */ +static void +link_recovery_mark_no_fallback(struct intel_dp_link_training *link_training) +{ + link_training->recovery_state = INTEL_DP_LINK_RECOVERY_NO_FALLBACK; +} + +/** + * link_recovery_reset - reset the link recovery state + * @link_training: link training state + * + * Reset the link recovery state to indicate that no link recovery is + * required. + */ +static void link_recovery_reset(struct intel_dp_link_training *link_training) +{ + link_training->recovery_state = INTEL_DP_LINK_RECOVERY_IDLE; +} + /** * intel_dp_stop_link_train - stop link training * @intel_dp: DP struct @@ -1266,6 +1775,7 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp, void intel_dp_stop_link_train(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { + struct intel_dp_link_training *link_training = intel_dp->link.training; struct intel_display *display = to_intel_display(intel_dp); struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; int ret; @@ -1286,8 +1796,8 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp, intel_hpd_unblock(encoder); if (!display->hotplug.ignore_long_hpd && - intel_dp->link.seq_train_failures < MAX_SEQ_TRAIN_FAILURES) { - int delay_ms = intel_dp->link.seq_train_failures ? 0 : 2000; + link_recovery_autoretrain_allowed(link_training)) { + int delay_ms = link_recovery_autoretrain_pending(link_training) ? 0 : 2000; intel_encoder_link_check_queue_work(encoder, delay_ms); } @@ -1340,18 +1850,23 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, int *new_link_rate, int *new_lane_count) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + struct intel_dp_link_config forced_params; int link_rate; int lane_count; int i; - i = intel_dp_link_config_index(intel_dp, crtc_state->port_clock, crtc_state->lane_count); - for (i--; i >= 0; i--) { - intel_dp_link_config_get(intel_dp, i, &link_rate, &lane_count); + intel_dp_link_caps_get_forced_params(link_caps, &forced_params); - if ((intel_dp->link.force_rate && - intel_dp->link.force_rate != link_rate) || - (intel_dp->link.force_lane_count && - intel_dp->link.force_lane_count != lane_count)) + i = intel_dp_link_config_index(intel_dp->link.caps, + crtc_state->port_clock, crtc_state->lane_count); + for (i--; i >= 0; i--) { + intel_dp_link_config_get(intel_dp->link.caps, i, &link_rate, &lane_count); + + if ((forced_params.rate && + forced_params.rate != link_rate) || + (forced_params.lane_count && + forced_params.lane_count != lane_count)) continue; break; @@ -1368,20 +1883,22 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp, static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + struct intel_dp_link_config forced_params; int rate_index; int new_rate; - if (intel_dp->link.force_rate) + intel_dp_link_caps_get_forced_params(link_caps, &forced_params); + if (forced_params.rate) return -1; - rate_index = intel_dp_rate_index(intel_dp->common_rates, - intel_dp->num_common_rates, - current_rate); + rate_index = intel_dp_link_caps_common_rate_idx(link_caps, + current_rate); if (rate_index <= 0) return -1; - new_rate = intel_dp_common_rate(intel_dp, rate_index - 1); + new_rate = intel_dp_common_rate(link_caps, rate_index - 1); /* TODO: Make switching from UHBR to non-UHBR rates work. */ if (drm_dp_is_uhbr_rate(current_rate) != drm_dp_is_uhbr_rate(new_rate)) @@ -1392,7 +1909,10 @@ static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate) static int reduce_lane_count(struct intel_dp *intel_dp, int current_lane_count) { - if (intel_dp->link.force_lane_count) + struct intel_dp_link_config forced_params; + + intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params); + if (forced_params.lane_count) return -1; if (current_lane_count == 1) @@ -1405,6 +1925,7 @@ static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state, int *new_link_rate, int *new_lane_count) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; int link_rate; int lane_count; @@ -1412,7 +1933,7 @@ static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp, link_rate = reduce_link_rate(intel_dp, crtc_state->port_clock); if (link_rate < 0) { lane_count = reduce_lane_count(intel_dp, crtc_state->lane_count); - link_rate = intel_dp_max_common_rate(intel_dp); + link_rate = intel_dp_max_common_rate(link_caps); } if (lane_count < 0) @@ -1439,6 +1960,8 @@ static bool reduce_link_params(struct intel_dp *intel_dp, const struct intel_crt static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + struct intel_dp_link_config max_link_limits; int new_link_rate; int new_lane_count; @@ -1464,8 +1987,11 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp, crtc_state->lane_count, crtc_state->port_clock, new_lane_count, new_link_rate); - intel_dp->link.max_rate = new_link_rate; - intel_dp->link.max_lane_count = new_lane_count; + max_link_limits.rate = new_link_rate; + max_link_limits.lane_count = new_lane_count; + + /* TODO: handle an update failure */ + intel_dp_link_caps_set_max_limits(link_caps, &max_link_limits); return 0; } @@ -1780,6 +2306,9 @@ void intel_dp_start_link_train(struct intel_atomic_state *state, struct intel_display *display = to_intel_display(state); struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *encoder = &dig_port->base; + struct intel_dp_link_training *link_training = + intel_dp->link.training; + bool autoretrain_allowed; bool passed; /* * Reinit the LTTPRs here to ensure that they are switched to @@ -1803,15 +2332,15 @@ void intel_dp_start_link_train(struct intel_atomic_state *state, else passed = intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count); - if (intel_dp->link.force_train_failure) { - intel_dp->link.force_train_failure--; + if (link_training->force_train_failure) { + link_training->force_train_failure--; lt_dbg(intel_dp, DP_PHY_DPRX, "Forcing link training failure\n"); } else if (passed) { - intel_dp->link.seq_train_failures = 0; + link_recovery_reset(link_training); return; } - intel_dp->link.seq_train_failures++; + autoretrain_allowed = link_recovery_mark_train_failure(link_training); /* * Ignore the link failure in CI @@ -1830,13 +2359,13 @@ void intel_dp_start_link_train(struct intel_atomic_state *state, return; } - if (intel_dp->link.seq_train_failures < MAX_SEQ_TRAIN_FAILURES) + if (autoretrain_allowed) return; if (intel_dp_schedule_fallback_link_training(state, intel_dp, crtc_state)) return; - intel_dp->link.retrain_disabled = true; + link_recovery_mark_no_fallback(link_training); if (!passed) lt_err(intel_dp, DP_PHY_DPRX, "Can't reduce link training parameters after failure\n"); @@ -1864,256 +2393,307 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp, lt_dbg(intel_dp, DP_PHY_DPRX, "DP2.0 SDP CRC16 for 128b/132b enabled\n"); } -static int i915_dp_force_link_rate_show(struct seq_file *m, void *data) +bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate, + u8 lane_count) { - struct intel_connector *connector = to_intel_connector(m->private); - struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); - int current_rate = -1; - int force_rate; - int err; - int i; + struct intel_dp_link_config max_link_limits; + + /* + * FIXME: we need to synchronize the current link parameters with + * hardware readout. Currently fast link training doesn't work on + * boot-up. + * + * NOTE: + * This may be called from both serialized (locked and synced against + * async commit tails) and unserialized (e.g. HPD IRQ) contexts. It + * uses the current max link limits as upper bounds to reject + * obviously bogus values, even if those bounds may be observed in a + * transient or slightly stale state. + * + * This is not a full validation of the link configuration. Even in + * serialized contexts, additional constraints (e.g. source limitations, + * bandwidth checks, and other atomic state dependencies) are only + * verified during the atomic check of the subsequent commit. + * + * max_link_limits only provides independent upper bounds for rate and + * lane count. Callers must not assume it is itself an allowed link + * configuration. Although that happens to be true for now, it will + * stop being guaranteed once fallback depends only on disabled configs. + */ + intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits); + + if (link_rate == 0 || + link_rate > max_link_limits.rate) + return false; + + if (lane_count == 0 || + lane_count > max_link_limits.lane_count) + return false; + + return true; +} + +static bool intel_dp_link_ok(struct intel_dp *intel_dp, + u8 link_status[DP_LINK_STATUS_SIZE]) +{ + struct intel_display *display = to_intel_display(intel_dp); + struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; + bool uhbr = intel_dp->link_rate >= 1000000; + bool ok; + + if (uhbr) + ok = drm_dp_128b132b_lane_channel_eq_done(link_status, + intel_dp->lane_count); + else + ok = drm_dp_channel_eq_ok(link_status, intel_dp->lane_count); + + if (ok) + return true; + + intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status); + drm_dbg_kms(display->drm, + "[ENCODER:%d:%s] %s link not ok, retraining\n", + encoder->base.base.id, encoder->base.name, + uhbr ? "128b/132b" : "8b/10b"); + + return false; +} + +static int +intel_dp_read_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE]) +{ + int err; + + memset(link_status, 0, DP_LINK_STATUS_SIZE); + + if (intel_dp_mst_active_streams(intel_dp) > 0) + err = drm_dp_dpcd_read_data(&intel_dp->aux, DP_LANE0_1_STATUS_ESI, + link_status, DP_LINK_STATUS_SIZE - 2); + else + err = drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX, + link_status); - err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); if (err) return err; - if (intel_dp->link.active) - current_rate = intel_dp->link_rate; - force_rate = intel_dp->link.force_rate; - - drm_modeset_unlock(&display->drm->mode_config.connection_mutex); - - seq_printf(m, "%sauto%s", - force_rate == 0 ? "[" : "", - force_rate == 0 ? "]" : ""); - - for (i = 0; i < intel_dp->num_source_rates; i++) - seq_printf(m, " %s%d%s%s", - intel_dp->source_rates[i] == force_rate ? "[" : "", - intel_dp->source_rates[i], - intel_dp->source_rates[i] == current_rate ? "*" : "", - intel_dp->source_rates[i] == force_rate ? "]" : ""); - - seq_putc(m, '\n'); + if (link_status[DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS] & + DP_DOWNSTREAM_PORT_STATUS_CHANGED) + WRITE_ONCE(intel_dp->downstream_port_changed, true); return 0; } -static int parse_link_rate(struct intel_dp *intel_dp, const char __user *ubuf, size_t len) +bool intel_dp_link_training_get_force_retrain(struct intel_dp_link_training *link_training) { - char *kbuf; - const char *p; - int rate; - int ret = 0; + return link_training->force_retrain; +} - kbuf = memdup_user_nul(ubuf, len); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); +static void intel_dp_link_training_set_force_retrain(struct intel_dp_link_training *link_training, + bool forced) +{ + link_training->force_retrain = forced; +} - p = strim(kbuf); +static bool +intel_dp_needs_link_retrain(struct intel_dp *intel_dp) +{ + struct intel_dp_link_training *link_training = intel_dp->link.training; + u8 link_status[DP_LINK_STATUS_SIZE]; - if (!strcmp(p, "auto")) { - rate = 0; - } else { - ret = kstrtoint(p, 0, &rate); - if (ret < 0) - goto out_free; + if (!intel_dp->link.active) + return false; - if (intel_dp_rate_index(intel_dp->source_rates, - intel_dp->num_source_rates, - rate) < 0) - ret = -EINVAL; + /* + * While PSR source HW is enabled, it will control main-link sending + * frames, enabling and disabling it so trying to do a retrain will fail + * as the link would or not be on or it could mix training patterns + * and frame data at the same time causing retrain to fail. + * Also when exiting PSR, HW will retrain the link anyways fixing + * any link status error. + */ + if (intel_psr_enabled(intel_dp)) + return false; + + if (intel_dp_link_training_get_force_retrain(link_training)) + return true; + + if (intel_dp_read_link_status(intel_dp, link_status) < 0) + return false; + + /* + * Validate the cached values of intel_dp->link_rate and + * intel_dp->lane_count before attempting to retrain. + * + * FIXME would be nice to user the crtc state here, but since + * we need to call this from the short HPD handler that seems + * a bit hard. + */ + if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate, + intel_dp->lane_count)) + return false; + + if (!link_recovery_autoretrain_allowed(link_training)) + return false; + + if (link_recovery_autoretrain_pending(link_training)) + return true; + + /* Retrain if link not ok */ + return !intel_dp_link_ok(intel_dp, link_status) && + !intel_psr_link_ok(intel_dp); +} + +static bool intel_dp_is_connected(struct intel_dp *intel_dp) +{ + struct intel_connector *connector = intel_dp->attached_connector; + + return connector->base.status == connector_status_connected || + intel_dp->is_mst; +} + +static void queue_modeset_retry_for_links_in_state(struct intel_atomic_state *state, + struct intel_encoder *encoder, + u8 pipe_mask) +{ + const struct intel_crtc_state *crtc_state; + struct intel_crtc *crtc; + + for_each_new_intel_crtc_in_state(state, crtc, crtc_state) { + if (!(BIT(crtc->pipe) & pipe_mask)) + continue; + + intel_dp_queue_modeset_retry_for_link(state, encoder, crtc_state); } - -out_free: - kfree(kbuf); - - return ret < 0 ? ret : rate; } -static ssize_t i915_dp_force_link_rate_write(struct file *file, - const char __user *ubuf, - size_t len, loff_t *offp) +static int intel_dp_retrain_link(struct intel_encoder *encoder, + struct drm_modeset_acquire_ctx *ctx) { - struct seq_file *m = file->private_data; - struct intel_connector *connector = to_intel_connector(m->private); - struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); - int rate; - int err; + struct intel_display *display = to_intel_display(encoder); + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct intel_dp_link_training *link_training = + intel_dp->link.training; + struct intel_atomic_state *state; + struct drm_atomic_commit *_state; + u8 pipe_mask; + int ret; - rate = parse_link_rate(intel_dp, ubuf, len); - if (rate < 0) - return rate; + if (!intel_dp_is_connected(intel_dp)) + return 0; - err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); - if (err) - return err; + ret = drm_modeset_lock(&display->drm->mode_config.connection_mutex, + ctx); + if (ret) + return ret; - intel_dp_reset_link_params(intel_dp); - intel_dp->link.force_rate = rate; + if (!intel_dp_needs_link_retrain(intel_dp)) + return 0; - drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + ret = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask); + if (ret) + return ret; - *offp += len; + if (pipe_mask == 0) + return 0; - return len; -} -DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_link_rate); + if (!intel_dp_needs_link_retrain(intel_dp)) + return 0; -static int i915_dp_force_lane_count_show(struct seq_file *m, void *data) -{ - struct intel_connector *connector = to_intel_connector(m->private); - struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); - int current_lane_count = -1; - int force_lane_count; - int err; - int i; + drm_dbg_kms(display->drm, + "[ENCODER:%d:%s] retraining link (forced %s)\n", + encoder->base.base.id, encoder->base.name, + str_yes_no(intel_dp_link_training_get_force_retrain(link_training))); - err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); - if (err) - return err; + _state = drm_atomic_commit_alloc(display->drm); + if (!_state) + return -ENOMEM; - if (intel_dp->link.active) - current_lane_count = intel_dp->lane_count; - force_lane_count = intel_dp->link.force_lane_count; + state = to_intel_atomic_state(_state); - drm_modeset_unlock(&display->drm->mode_config.connection_mutex); + ret = intel_modeset_commit_pipes_for_atomic_state(state, pipe_mask, ctx); + if (ret == -EDEADLK) + goto out; - seq_printf(m, "%sauto%s", - force_lane_count == 0 ? "[" : "", - force_lane_count == 0 ? "]" : ""); + intel_dp_link_training_set_force_retrain(link_training, false); - for (i = 1; i <= 4; i <<= 1) - seq_printf(m, " %s%d%s%s", - i == force_lane_count ? "[" : "", - i, - i == current_lane_count ? "*" : "", - i == force_lane_count ? "]" : ""); - - seq_putc(m, '\n'); - - return 0; -} - -static int parse_lane_count(const char __user *ubuf, size_t len) -{ - char *kbuf; - const char *p; - int lane_count; - int ret = 0; - - kbuf = memdup_user_nul(ubuf, len); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - - p = strim(kbuf); - - if (!strcmp(p, "auto")) { - lane_count = 0; - } else { - ret = kstrtoint(p, 0, &lane_count); - if (ret < 0) - goto out_free; - - switch (lane_count) { - case 1: - case 2: - case 4: - break; - default: - ret = -EINVAL; - } + if (ret) { + drm_dbg_kms(display->drm, + "[ENCODER:%d:%s] link retraining failed: %pe\n", + encoder->base.base.id, encoder->base.name, + ERR_PTR(ret)); + /* + * intel_dp_needs_link_retrain() only performs a coarse check of + * retrainability, so the modeset commit may still fail. Disable + * further auto-retrain attempts in that case. + * + * A sink capability change may restore the retrainable state (see + * intel_dp_update_sink_caps(), intel_dp_reset_link_params()), + * allowing retraining to be attempted again. + */ + link_recovery_mark_autoretrain_modeset_failure(link_training); + queue_modeset_retry_for_links_in_state(state, encoder, pipe_mask); } +out: + drm_atomic_commit_put(&state->base); -out_free: - kfree(kbuf); - - return ret < 0 ? ret : lane_count; + return ret; } -static ssize_t i915_dp_force_lane_count_write(struct file *file, - const char __user *ubuf, - size_t len, loff_t *offp) +void intel_dp_link_check(struct intel_encoder *encoder) { - struct seq_file *m = file->private_data; - struct intel_connector *connector = to_intel_connector(m->private); - struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); - int lane_count; - int err; + struct drm_modeset_acquire_ctx ctx; + int ret; - lane_count = parse_lane_count(ubuf, len); - if (lane_count < 0) - return lane_count; - - err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); - if (err) - return err; - - intel_dp_reset_link_params(intel_dp); - intel_dp->link.force_lane_count = lane_count; - - drm_modeset_unlock(&display->drm->mode_config.connection_mutex); - - *offp += len; - - return len; + intel_modeset_lock_ctx_retry(&ctx, NULL, 0, ret) + ret = intel_dp_retrain_link(encoder, &ctx); } -DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_lane_count); -static int i915_dp_max_link_rate_show(void *data, u64 *val) +void intel_dp_check_link_state(struct intel_dp *intel_dp) { - struct intel_connector *connector = to_intel_connector(data); - struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); - int err; + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct intel_encoder *encoder = &dig_port->base; - err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); - if (err) - return err; + if (!intel_dp_is_connected(intel_dp)) + return; - *val = intel_dp->link.max_rate; + /* + * NOTE: + * This may race with an ongoing modeset updating the max link limits + * and, with that, the link's retrainability, so + * intel_dp_needs_link_retrain() may observe stale state. + * + * This is harmless: stale params captured as valid may spuriously + * allow retraining here, but the decision is rechecked later in a + * properly serialized context. + * + * Conversely, stale params captured as invalid may skip retraining, + * but that can only happen before the modeset has completed its own + * link training for the new, valid configuration, after which the + * link state is rechecked. + * + * See intel_dp_link_params_valid() for capturing and validating the + * params. + */ + if (!intel_dp_needs_link_retrain(intel_dp)) + return; - drm_modeset_unlock(&display->drm->mode_config.connection_mutex); - - return 0; + intel_encoder_link_check_queue_work(encoder, 0); } -DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_link_rate_fops, i915_dp_max_link_rate_show, NULL, "%llu\n"); - -static int i915_dp_max_lane_count_show(void *data, u64 *val) -{ - struct intel_connector *connector = to_intel_connector(data); - struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); - int err; - - err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); - if (err) - return err; - - *val = intel_dp->link.max_lane_count; - - drm_modeset_unlock(&display->drm->mode_config.connection_mutex); - - return 0; -} -DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_lane_count_fops, i915_dp_max_lane_count_show, NULL, "%llu\n"); static int i915_dp_force_link_training_failure_show(void *data, u64 *val) { struct intel_connector *connector = to_intel_connector(data); struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_training *link_training = connector_to_link_training(connector); int err; err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); if (err) return err; - *val = intel_dp->link.force_train_failure; + intel_dp_flush_connector_commits(connector); + + *val = link_training->force_train_failure; drm_modeset_unlock(&display->drm->mode_config.connection_mutex); @@ -2124,7 +2704,7 @@ static int i915_dp_force_link_training_failure_write(void *data, u64 val) { struct intel_connector *connector = to_intel_connector(data); struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_training *link_training = connector_to_link_training(connector); int err; if (val > 2) @@ -2134,7 +2714,9 @@ static int i915_dp_force_link_training_failure_write(void *data, u64 val) if (err) return err; - intel_dp->link.force_train_failure = val; + intel_dp_flush_connector_commits(connector); + + link_training->force_train_failure = val; drm_modeset_unlock(&display->drm->mode_config.connection_mutex); @@ -2148,14 +2730,16 @@ static int i915_dp_force_link_retrain_show(void *data, u64 *val) { struct intel_connector *connector = to_intel_connector(data); struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_training *link_training = connector_to_link_training(connector); int err; err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); if (err) return err; - *val = intel_dp->link.force_retrain; + intel_dp_flush_connector_commits(connector); + + *val = intel_dp_link_training_get_force_retrain(link_training); drm_modeset_unlock(&display->drm->mode_config.connection_mutex); @@ -2166,14 +2750,17 @@ static int i915_dp_force_link_retrain_write(void *data, u64 val) { struct intel_connector *connector = to_intel_connector(data); struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_training *link_training = connector_to_link_training(connector); + struct intel_dp *intel_dp = link_training->dp; int err; err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); if (err) return err; - intel_dp->link.force_retrain = val; + intel_dp_flush_connector_commits(connector); + + intel_dp_link_training_set_force_retrain(link_training, val); drm_modeset_unlock(&display->drm->mode_config.connection_mutex); @@ -2189,14 +2776,17 @@ static int i915_dp_link_retrain_disabled_show(struct seq_file *m, void *data) { struct intel_connector *connector = to_intel_connector(m->private); struct intel_display *display = to_intel_display(connector); - struct intel_dp *intel_dp = intel_attached_dp(connector); + struct intel_dp_link_training *link_training = connector_to_link_training(connector); int err; err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex); if (err) return err; - seq_printf(m, "%s\n", str_yes_no(intel_dp->link.retrain_disabled)); + intel_dp_flush_connector_commits(connector); + + /* TODO: Expose this via a debugfs entry reflecting what the state represents. */ + seq_printf(m, "%s\n", str_yes_no(link_recovery_has_no_fallback(link_training))); drm_modeset_unlock(&display->drm->mode_config.connection_mutex); @@ -2212,18 +2802,6 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector) connector->base.connector_type != DRM_MODE_CONNECTOR_eDP) return; - debugfs_create_file("i915_dp_force_link_rate", 0644, root, - connector, &i915_dp_force_link_rate_fops); - - debugfs_create_file("i915_dp_force_lane_count", 0644, root, - connector, &i915_dp_force_lane_count_fops); - - debugfs_create_file("i915_dp_max_link_rate", 0444, root, - connector, &i915_dp_max_link_rate_fops); - - debugfs_create_file("i915_dp_max_lane_count", 0444, root, - connector, &i915_dp_max_lane_count_fops); - debugfs_create_file("i915_dp_force_link_training_failure", 0644, root, connector, &i915_dp_force_link_training_failure_fops); @@ -2233,3 +2811,26 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector) debugfs_create_file("i915_dp_link_retrain_disabled", 0444, root, connector, &i915_dp_link_retrain_disabled_fops); } + +void intel_dp_link_training_reset(struct intel_dp_link_training *link_training) +{ + link_recovery_reset(link_training); +} + +struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp) +{ + struct intel_dp_link_training *link_training; + + link_training = kzalloc_obj(*link_training); + if (!link_training) + return NULL; + + link_training->dp = intel_dp; + + return link_training; +} + +void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training) +{ + kfree(link_training); +} diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h index 18c34c1a472f..ef16fcabd6da 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h @@ -12,6 +12,8 @@ struct intel_atomic_state; struct intel_connector; struct intel_crtc_state; struct intel_dp; +struct intel_dp_link_training; +struct intel_encoder; int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]); int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp); @@ -54,6 +56,19 @@ static inline u8 intel_dp_training_pattern_symbol(u8 pattern) void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state); +bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate, + u8 lane_count); + +bool intel_dp_link_training_get_force_retrain(struct intel_dp_link_training *link_training); + +void intel_dp_link_check(struct intel_encoder *encoder); +void intel_dp_check_link_state(struct intel_dp *intel_dp); + void intel_dp_link_training_debugfs_add(struct intel_connector *connector); +void intel_dp_link_training_reset(struct intel_dp_link_training *link_training); + +struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp); +void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training); + #endif /* __INTEL_DP_LINK_TRAINING_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c index 0aa3e6b4c781..ecc90e8faee1 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c @@ -697,12 +697,12 @@ static int mst_stream_compute_link_for_joined_pipes(struct intel_encoder *encode return 0; } -static int mst_stream_compute_config(struct intel_encoder *encoder, +static int mst_stream_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { struct intel_display *display = to_intel_display(encoder); - struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); struct intel_dp *intel_dp = to_primary_dp(encoder); struct intel_connector *connector = @@ -925,11 +925,11 @@ int intel_dp_mst_atomic_check_link(struct intel_atomic_state *state, return 0; } -static int mst_stream_compute_config_late(struct intel_encoder *encoder, +static int mst_stream_compute_config_late(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct intel_atomic_state *state = to_intel_atomic_state(conn_state->state); struct intel_dp *intel_dp = to_primary_dp(encoder); /* lowest numbered transcoder will be designated master */ diff --git a/drivers/gpu/drm/i915/display/intel_dp_test.c b/drivers/gpu/drm/i915/display/intel_dp_test.c index ba44769c9cfb..da7632536dac 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_test.c +++ b/drivers/gpu/drm/i915/display/intel_dp_test.c @@ -14,6 +14,7 @@ #include "intel_display_regs.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_dp_link_caps.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" #include "intel_dp_test.h" @@ -32,6 +33,7 @@ void intel_dp_test_compute_config(struct intel_dp *intel_dp, struct intel_crtc_state *pipe_config, struct link_config_limits *limits) { + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; struct intel_display *display = to_intel_display(intel_dp); /* For DP Compliance we override the computed bpp for the pipe */ @@ -54,9 +56,8 @@ void intel_dp_test_compute_config(struct intel_dp *intel_dp, */ if (intel_dp_link_params_valid(intel_dp, intel_dp->compliance.test_link_rate, intel_dp->compliance.test_lane_count)) { - index = intel_dp_rate_index(intel_dp->common_rates, - intel_dp->num_common_rates, - intel_dp->compliance.test_link_rate); + index = intel_dp_link_caps_common_rate_idx(link_caps, + intel_dp->compliance.test_link_rate); if (index >= 0) { limits->min_rate = intel_dp->compliance.test_link_rate; limits->max_rate = intel_dp->compliance.test_link_rate; diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c index d6bd1f7e01e1..76e9753766b9 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c @@ -11,6 +11,7 @@ #include "intel_display_limits.h" #include "intel_display_types.h" #include "intel_dp.h" +#include "intel_dp_link_caps.h" #include "intel_dp_link_training.h" #include "intel_dp_mst.h" #include "intel_dp_tunnel.h" @@ -56,8 +57,9 @@ static int kbytes_to_mbits(int kbytes) static int get_current_link_bw(struct intel_dp *intel_dp) { - int rate = intel_dp_max_common_rate(intel_dp); - int lane_count = intel_dp_max_common_lane_count(intel_dp); + struct intel_dp_link_caps *link_caps = intel_dp->link.caps; + int rate = intel_dp_max_common_rate(link_caps); + int lane_count = intel_dp_link_caps_max_common_lane_count(link_caps); return intel_dp_max_link_data_rate(intel_dp, rate, lane_count); } diff --git a/drivers/gpu/drm/i915/display/intel_dsb.c b/drivers/gpu/drm/i915/display/intel_dsb.c index fec8a56e21ea..d9a270362a82 100644 --- a/drivers/gpu/drm/i915/display/intel_dsb.c +++ b/drivers/gpu/drm/i915/display/intel_dsb.c @@ -210,6 +210,18 @@ static int dsb_scanline_to_hw(struct intel_atomic_state *state, return (scanline + vtotal - intel_crtc_scanline_offset(crtc_state)) % vtotal; } +static +bool pre_commit_use_safe_window(struct intel_atomic_state *state, + struct intel_crtc *crtc) +{ + struct intel_display *display = to_intel_display(crtc->base.dev); + + if (intel_vrr_always_use_vrr_tg(display)) + return true; + + return pre_commit_is_vrr_active(state, crtc); +} + /* * Bspec suggests that we should always set DSB_SKIP_WAITS_EN. We have approach * different from what is explained in Bspec on how flip is considered being @@ -229,7 +241,7 @@ static u32 dsb_chicken(struct intel_atomic_state *state, u32 chicken = intel_psr_use_trans_push(new_crtc_state) ? DSB_SKIP_WAITS_EN : 0; - if (pre_commit_is_vrr_active(state, crtc)) + if (pre_commit_use_safe_window(state, crtc)) chicken |= DSB_CTRL_WAIT_SAFE_WINDOW | DSB_CTRL_NO_WAIT_VBLANK | DSB_INST_WAIT_SAFE_WINDOW | @@ -798,6 +810,12 @@ void intel_dsb_vblank_evade(struct intel_atomic_state *state, end = intel_vrr_vmax_vblank_start(crtc_state); start = end - vblank_delay - latency; intel_dsb_wait_scanline_out(state, dsb, start, end); + } else if (pre_commit_use_safe_window(state, crtc)) { + int vblank_delay = crtc_state->set_context_latency; + + end = intel_mode_vblank_start(&crtc_state->hw.adjusted_mode); + start = end - vblank_delay - latency; + intel_dsb_wait_scanline_out(state, dsb, start, end); } else { int vblank_delay = intel_mode_vblank_delay(&crtc_state->hw.adjusted_mode); @@ -891,7 +909,7 @@ void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, &crtc_state->hw.adjusted_mode; int wait_scanlines; - if (pre_commit_is_vrr_active(state, crtc)) { + if (pre_commit_use_safe_window(state, crtc)) { /* * If the push happened before the vmin decision boundary * we don't know how far we are from the undelayed vblank. @@ -902,9 +920,17 @@ void intel_dsb_wait_for_delayed_vblank(struct intel_atomic_state *state, * the hardware itself guarantees that we're SCL lines * away from the delayed vblank, and we won't be inside * the vmin safe window so this extra wait does nothing. + * + * Experimentally, DSB may observe a slightly stale + * PIPEDSL value. When the actual scanline has just reached + * safe_window_start, WAIT_DSL_OUT may complete immediately + * due to the stale value. + * + * Shift the start back by one scanline to ensure the wait + * window is entered reliably. */ intel_dsb_wait_scanline_out(state, dsb, - intel_vrr_safe_window_start(crtc_state), + intel_vrr_safe_window_start(crtc_state) - 1, intel_vrr_vmin_safe_window_end(crtc_state)); /* * When the push is sent during vblank it will trigger diff --git a/drivers/gpu/drm/i915/display/intel_dvo.c b/drivers/gpu/drm/i915/display/intel_dvo.c index dd1a995c2979..f157699a7c4c 100644 --- a/drivers/gpu/drm/i915/display/intel_dvo.c +++ b/drivers/gpu/drm/i915/display/intel_dvo.c @@ -242,7 +242,8 @@ intel_dvo_mode_valid(struct drm_connector *_connector, return intel_dvo->dev.dev_ops->mode_valid(&intel_dvo->dev, mode); } -static int intel_dvo_compute_config(struct intel_encoder *encoder, +static int intel_dvo_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { @@ -256,7 +257,7 @@ static int intel_dvo_compute_config(struct intel_encoder *encoder, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - ret = intel_panel_compute_config(connector, adjusted_mode); + ret = intel_panel_compute_config(state, pipe_config, connector); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index 049157c41fe2..60a70dea5d85 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -54,21 +54,21 @@ struct intel_gmbus { }; enum gmbus_gpio { - GPIOA, - GPIOB, - GPIOC, - GPIOD, - GPIOE, - GPIOF, - GPIOG, - GPIOH, - __GPIOI_UNUSED, - GPIOJ, - GPIOK, - GPIOL, - GPIOM, - GPION, - GPIOO, + GPIO_0, + GPIO_1, + GPIO_2, + GPIO_3, + GPIO_4, + GPIO_5, + GPIO_6, + GPIO_7, + GPIO_8, + GPIO_9, + GPIO_10, + GPIO_11, + GPIO_12, + GPIO_13, + GPIO_14, }; struct gmbus_pin { @@ -78,77 +78,82 @@ struct gmbus_pin { /* Map gmbus pin pairs to names and registers. */ static const struct gmbus_pin gmbus_pins[] = { - [GMBUS_PIN_SSC] = { "ssc", GPIOB }, - [GMBUS_PIN_VGADDC] = { "vga", GPIOA }, - [GMBUS_PIN_PANEL] = { "panel", GPIOC }, - [GMBUS_PIN_DPC] = { "dpc", GPIOD }, - [GMBUS_PIN_DPB] = { "dpb", GPIOE }, - [GMBUS_PIN_DPD] = { "dpd", GPIOF }, + [GMBUS_PIN_SSC] = { "ssc", GPIO_1 }, + [GMBUS_PIN_VGADDC] = { "vga", GPIO_0 }, + [GMBUS_PIN_PANEL] = { "panel", GPIO_2 }, + [GMBUS_PIN_DPC] = { "dpc", GPIO_3 }, + [GMBUS_PIN_DPB] = { "dpb", GPIO_4 }, + [GMBUS_PIN_DPD] = { "dpd", GPIO_5 }, }; -static const struct gmbus_pin gmbus_pins_bdw[] = { - [GMBUS_PIN_VGADDC] = { "vga", GPIOA }, - [GMBUS_PIN_DPC] = { "dpc", GPIOD }, - [GMBUS_PIN_DPB] = { "dpb", GPIOE }, - [GMBUS_PIN_DPD] = { "dpd", GPIOF }, +static const struct gmbus_pin gmbus_pins_lpt_h[] = { + [GMBUS_PIN_VGADDC] = { "vga", GPIO_0 }, + [GMBUS_PIN_DPC] = { "dpc", GPIO_3 }, + [GMBUS_PIN_DPB] = { "dpb", GPIO_4 }, + [GMBUS_PIN_DPD] = { "dpd", GPIO_5 }, }; -static const struct gmbus_pin gmbus_pins_skl[] = { - [GMBUS_PIN_DPC] = { "dpc", GPIOD }, - [GMBUS_PIN_DPB] = { "dpb", GPIOE }, - [GMBUS_PIN_DPD] = { "dpd", GPIOF }, +static const struct gmbus_pin gmbus_pins_lpt_lp[] = { + [GMBUS_PIN_DPC] = { "dpc", GPIO_3 }, + [GMBUS_PIN_DPB] = { "dpb", GPIO_4 }, +}; + +static const struct gmbus_pin gmbus_pins_spt[] = { + [GMBUS_PIN_DPC] = { "dpc", GPIO_3 }, + [GMBUS_PIN_DPB] = { "dpb", GPIO_4 }, + [GMBUS_PIN_DPD] = { "dpd", GPIO_5 }, }; static const struct gmbus_pin gmbus_pins_bxt[] = { - [GMBUS_PIN_1_BXT] = { "dpb", GPIOB }, - [GMBUS_PIN_2_BXT] = { "dpc", GPIOC }, - [GMBUS_PIN_3_BXT] = { "misc", GPIOD }, + [GMBUS_PIN_1] = { "dpb", GPIO_1 }, + [GMBUS_PIN_2] = { "dpc", GPIO_2 }, + [GMBUS_PIN_3] = { "misc", GPIO_3 }, }; static const struct gmbus_pin gmbus_pins_cnp[] = { - [GMBUS_PIN_1_BXT] = { "dpb", GPIOB }, - [GMBUS_PIN_2_BXT] = { "dpc", GPIOC }, - [GMBUS_PIN_3_BXT] = { "misc", GPIOD }, - [GMBUS_PIN_4_CNP] = { "dpd", GPIOE }, + [GMBUS_PIN_1] = { "dpb", GPIO_1 }, + [GMBUS_PIN_2] = { "dpc", GPIO_2 }, + [GMBUS_PIN_3] = { "misc", GPIO_3 }, + [GMBUS_PIN_4] = { "dpd", GPIO_4 }, }; static const struct gmbus_pin gmbus_pins_icp[] = { - [GMBUS_PIN_1_BXT] = { "dpa", GPIOB }, - [GMBUS_PIN_2_BXT] = { "dpb", GPIOC }, - [GMBUS_PIN_3_BXT] = { "dpc", GPIOD }, - [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ }, - [GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOK }, - [GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOL }, - [GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOM }, - [GMBUS_PIN_13_TC5_TGP] = { "tc5", GPION }, - [GMBUS_PIN_14_TC6_TGP] = { "tc6", GPIOO }, + [GMBUS_PIN_1] = { "dpa", GPIO_1 }, + [GMBUS_PIN_2] = { "dpb", GPIO_2 }, + [GMBUS_PIN_3] = { "dpc", GPIO_3 }, + [GMBUS_PIN_9_TC1] = { "tc1", GPIO_9 }, + [GMBUS_PIN_10_TC2] = { "tc2", GPIO_10 }, + [GMBUS_PIN_11_TC3] = { "tc3", GPIO_11 }, + [GMBUS_PIN_12_TC4] = { "tc4", GPIO_12 }, + [GMBUS_PIN_13_TC5] = { "tc5", GPIO_13 }, + [GMBUS_PIN_14_TC6] = { "tc6", GPIO_14 }, }; static const struct gmbus_pin gmbus_pins_dg1[] = { - [GMBUS_PIN_1_BXT] = { "dpa", GPIOB }, - [GMBUS_PIN_2_BXT] = { "dpb", GPIOC }, - [GMBUS_PIN_3_BXT] = { "dpc", GPIOD }, - [GMBUS_PIN_4_CNP] = { "dpd", GPIOE }, + [GMBUS_PIN_1] = { "dpa", GPIO_1 }, + [GMBUS_PIN_2] = { "dpb", GPIO_2 }, + [GMBUS_PIN_3] = { "dpc", GPIO_3 }, + [GMBUS_PIN_4] = { "dpd", GPIO_4 }, }; static const struct gmbus_pin gmbus_pins_dg2[] = { - [GMBUS_PIN_1_BXT] = { "dpa", GPIOB }, - [GMBUS_PIN_2_BXT] = { "dpb", GPIOC }, - [GMBUS_PIN_3_BXT] = { "dpc", GPIOD }, - [GMBUS_PIN_4_CNP] = { "dpd", GPIOE }, - [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ }, + [GMBUS_PIN_1] = { "dpa", GPIO_1 }, + [GMBUS_PIN_2] = { "dpb", GPIO_2 }, + [GMBUS_PIN_3] = { "dpc", GPIO_3 }, + [GMBUS_PIN_4] = { "dpd", GPIO_4 }, + [GMBUS_PIN_9_TC1] = { "tc1", GPIO_9 }, }; static const struct gmbus_pin gmbus_pins_mtp[] = { - [GMBUS_PIN_1_BXT] = { "dpa", GPIOB }, - [GMBUS_PIN_2_BXT] = { "dpb", GPIOC }, - [GMBUS_PIN_3_BXT] = { "dpc", GPIOD }, - [GMBUS_PIN_4_CNP] = { "dpd", GPIOE }, - [GMBUS_PIN_5_MTP] = { "dpe", GPIOF }, - [GMBUS_PIN_9_TC1_ICP] = { "tc1", GPIOJ }, - [GMBUS_PIN_10_TC2_ICP] = { "tc2", GPIOK }, - [GMBUS_PIN_11_TC3_ICP] = { "tc3", GPIOL }, - [GMBUS_PIN_12_TC4_ICP] = { "tc4", GPIOM }, + [GMBUS_PIN_1] = { "dpa", GPIO_1 }, + [GMBUS_PIN_2] = { "dpb", GPIO_2 }, + [GMBUS_PIN_3] = { "dpc", GPIO_3 }, + [GMBUS_PIN_4] = { "dpd", GPIO_4 }, + [GMBUS_PIN_5] = { "dpe", GPIO_5 }, + [GMBUS_PIN_9_TC1] = { "tc1", GPIO_9 }, + [GMBUS_PIN_10_TC2] = { "tc2", GPIO_10 }, + [GMBUS_PIN_11_TC3] = { "tc3", GPIO_11 }, + [GMBUS_PIN_12_TC4] = { "tc4", GPIO_12 }, }; static const struct gmbus_pin *get_gmbus_pin(struct intel_display *display, @@ -175,12 +180,15 @@ static const struct gmbus_pin *get_gmbus_pin(struct intel_display *display, } else if (display->platform.geminilake || display->platform.broxton) { pins = gmbus_pins_bxt; size = ARRAY_SIZE(gmbus_pins_bxt); - } else if (DISPLAY_VER(display) == 9) { - pins = gmbus_pins_skl; - size = ARRAY_SIZE(gmbus_pins_skl); - } else if (display->platform.broadwell) { - pins = gmbus_pins_bdw; - size = ARRAY_SIZE(gmbus_pins_bdw); + } else if (HAS_PCH_SPT(display)) { + pins = gmbus_pins_spt; + size = ARRAY_SIZE(gmbus_pins_spt); + } else if (HAS_PCH_LPT_LP(display)) { + pins = gmbus_pins_lpt_lp; + size = ARRAY_SIZE(gmbus_pins_lpt_lp); + } else if (HAS_PCH_LPT(display)) { + pins = gmbus_pins_lpt_h; + size = ARRAY_SIZE(gmbus_pins_lpt_h); } else { pins = gmbus_pins; size = ARRAY_SIZE(gmbus_pins); diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.h b/drivers/gpu/drm/i915/display/intel_gmbus.h index 35a200a9efc0..5fdeab1aa794 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.h +++ b/drivers/gpu/drm/i915/display/intel_gmbus.h @@ -20,17 +20,17 @@ struct intel_display; #define GMBUS_PIN_DPB 5 /* SDVO, HDMIB */ #define GMBUS_PIN_DPD 6 /* HDMID */ #define GMBUS_PIN_RESERVED 7 /* 7 reserved */ -#define GMBUS_PIN_1_BXT 1 /* BXT+ (atom) and CNP+ (big core) */ -#define GMBUS_PIN_2_BXT 2 -#define GMBUS_PIN_3_BXT 3 -#define GMBUS_PIN_4_CNP 4 -#define GMBUS_PIN_5_MTP 5 -#define GMBUS_PIN_9_TC1_ICP 9 -#define GMBUS_PIN_10_TC2_ICP 10 -#define GMBUS_PIN_11_TC3_ICP 11 -#define GMBUS_PIN_12_TC4_ICP 12 -#define GMBUS_PIN_13_TC5_TGP 13 -#define GMBUS_PIN_14_TC6_TGP 14 +#define GMBUS_PIN_1 1 /* BXT+ (atom) and CNP+ (big core) */ +#define GMBUS_PIN_2 2 +#define GMBUS_PIN_3 3 +#define GMBUS_PIN_4 4 +#define GMBUS_PIN_5 5 +#define GMBUS_PIN_9_TC1 9 /* ICP+ */ +#define GMBUS_PIN_10_TC2 10 +#define GMBUS_PIN_11_TC3 11 +#define GMBUS_PIN_12_TC4 12 +#define GMBUS_PIN_13_TC5 13 +#define GMBUS_PIN_14_TC6 14 #define GMBUS_NUM_PINS 15 /* including 0 */ diff --git a/drivers/gpu/drm/i915/display/intel_hdcp.c b/drivers/gpu/drm/i915/display/intel_hdcp.c index e88fec24af49..0a076d2ed70a 100644 --- a/drivers/gpu/drm/i915/display/intel_hdcp.c +++ b/drivers/gpu/drm/i915/display/intel_hdcp.c @@ -145,6 +145,9 @@ intel_hdcp_required_content_stream(struct intel_atomic_state *state, if (!new_conn_state || !new_conn_state->crtc) continue; + if (drm_WARN_ON(display->drm, data->k >= INTEL_NUM_PIPES(display))) + return -EINVAL; + data->streams[data->k].stream_id = intel_conn_to_vcpi(state, connector); data->k++; @@ -155,7 +158,7 @@ intel_hdcp_required_content_stream(struct intel_atomic_state *state, } drm_connector_list_iter_end(&conn_iter); - if (drm_WARN_ON(display->drm, data->k > INTEL_NUM_PIPES(display) || data->k == 0)) + if (drm_WARN_ON(display->drm, !data->k)) return -EINVAL; /* @@ -1798,9 +1801,10 @@ int hdcp2_authenticate_repeater_topology(struct intel_connector *connector) return -EINVAL; } - if (seq_num_v < hdcp->seq_num_v) { - /* Roll over of the seq_num_v from repeater. Reauthenticate. */ - drm_dbg_kms(display->drm, "Seq_num_v roll over.\n"); + if (hdcp->hdcp2_encrypted && seq_num_v <= hdcp->seq_num_v) { + /* Reauthenticate on Seq_num_v repeat or rollover */ + drm_dbg_kms(display->drm, "Seq_num_v %s\n", + seq_num_v == hdcp->seq_num_v ? "repeat" : "rollover"); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.c b/drivers/gpu/drm/i915/display/intel_hdmi.c index 9076c2b176ec..8a019d3574df 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.c +++ b/drivers/gpu/drm/i915/display/intel_hdmi.c @@ -71,7 +71,7 @@ bool intel_hdmi_is_frl(u32 clock) { - u32 rates[] = { 300000, 600000, 800000, 1000000, 1200000 }; + static const u32 rates[] = { 300000, 600000, 800000, 1000000, 1200000 }; int i; for (i = 0; i < ARRAY_SIZE(rates); i++) @@ -2728,6 +2728,32 @@ intel_hdmi_add_properties(struct intel_hdmi *intel_hdmi, struct drm_connector *_ drm_connector_attach_max_bpc_property(&connector->base, 8, 12); } +/* + * HDMI 2.0 spec, section 6.1.3.1 (Scrambling Control): after + * enabling Scrambling_Enable and starting scrambled video + * transmission, poll Scrambling_Status for up to 200 ms. + */ +void +intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_state, + struct drm_connector *_connector) +{ + struct intel_connector *connector = to_intel_connector(_connector); + struct intel_display *display = to_intel_display(crtc_state); + bool scrambling_enabled = false; + int ret; + + if (!crtc_state->hdmi_scrambling) + return; + + /* Poll for a max of 200 msec as per HDMI spec */ + ret = poll_timeout_us(scrambling_enabled = drm_scdc_get_scrambling_status(&connector->base), + scrambling_enabled, 1000, 200 * 1000, false); + if (ret) + drm_dbg_kms(display->drm, + "[CONNECTOR:%d:%s] Timed out waiting for scrambling enable\n", + connector->base.base.id, connector->base.name); +} + /* * intel_hdmi_handle_sink_scrambling: handle sink scrambling/clock ratio setup * @encoder: intel_encoder @@ -2799,14 +2825,14 @@ static u8 bxt_encoder_to_ddc_pin(struct intel_encoder *encoder) switch (port) { case PORT_B: - ddc_pin = GMBUS_PIN_1_BXT; + ddc_pin = GMBUS_PIN_1; break; case PORT_C: - ddc_pin = GMBUS_PIN_2_BXT; + ddc_pin = GMBUS_PIN_2; break; default: MISSING_CASE(port); - ddc_pin = GMBUS_PIN_1_BXT; + ddc_pin = GMBUS_PIN_1; break; } return ddc_pin; @@ -2819,20 +2845,17 @@ static u8 cnp_encoder_to_ddc_pin(struct intel_encoder *encoder) switch (port) { case PORT_B: - ddc_pin = GMBUS_PIN_1_BXT; + ddc_pin = GMBUS_PIN_1; break; case PORT_C: - ddc_pin = GMBUS_PIN_2_BXT; + ddc_pin = GMBUS_PIN_2; break; case PORT_D: - ddc_pin = GMBUS_PIN_4_CNP; - break; - case PORT_F: - ddc_pin = GMBUS_PIN_3_BXT; + ddc_pin = GMBUS_PIN_4; break; default: MISSING_CASE(port); - ddc_pin = GMBUS_PIN_1_BXT; + ddc_pin = GMBUS_PIN_1; break; } return ddc_pin; @@ -2844,12 +2867,12 @@ static u8 icl_encoder_to_ddc_pin(struct intel_encoder *encoder) enum port port = encoder->port; if (intel_encoder_is_combo(encoder)) - return GMBUS_PIN_1_BXT + port; + return GMBUS_PIN_1 + port; else if (intel_encoder_is_tc(encoder)) - return GMBUS_PIN_9_TC1_ICP + intel_encoder_to_tc(encoder); + return GMBUS_PIN_9_TC1 + intel_encoder_to_tc(encoder); drm_WARN(display->drm, 1, "Unknown port:%c\n", port_name(port)); - return GMBUS_PIN_2_BXT; + return GMBUS_PIN_2; } static u8 mcc_encoder_to_ddc_pin(struct intel_encoder *encoder) @@ -2859,17 +2882,17 @@ static u8 mcc_encoder_to_ddc_pin(struct intel_encoder *encoder) switch (phy) { case PHY_A: - ddc_pin = GMBUS_PIN_1_BXT; + ddc_pin = GMBUS_PIN_1; break; case PHY_B: - ddc_pin = GMBUS_PIN_2_BXT; + ddc_pin = GMBUS_PIN_2; break; case PHY_C: - ddc_pin = GMBUS_PIN_9_TC1_ICP; + ddc_pin = GMBUS_PIN_9_TC1; break; default: MISSING_CASE(phy); - ddc_pin = GMBUS_PIN_1_BXT; + ddc_pin = GMBUS_PIN_1; break; } return ddc_pin; @@ -2889,9 +2912,9 @@ static u8 rkl_encoder_to_ddc_pin(struct intel_encoder *encoder) * all outputs. */ if (INTEL_PCH_TYPE(display) >= PCH_TGP && phy >= PHY_C) - return GMBUS_PIN_9_TC1_ICP + phy - PHY_C; + return GMBUS_PIN_9_TC1 + phy - PHY_C; - return GMBUS_PIN_1_BXT + phy; + return GMBUS_PIN_1 + phy; } static u8 gen9bc_tgp_encoder_to_ddc_pin(struct intel_encoder *encoder) @@ -2908,9 +2931,9 @@ static u8 gen9bc_tgp_encoder_to_ddc_pin(struct intel_encoder *encoder) * all outputs. */ if (INTEL_PCH_TYPE(display) >= PCH_TGP && phy >= PHY_C) - return GMBUS_PIN_9_TC1_ICP + phy - PHY_C; + return GMBUS_PIN_9_TC1 + phy - PHY_C; - return GMBUS_PIN_1_BXT + phy; + return GMBUS_PIN_1 + phy; } static u8 dg1_encoder_to_ddc_pin(struct intel_encoder *encoder) @@ -2929,9 +2952,9 @@ static u8 adls_encoder_to_ddc_pin(struct intel_encoder *encoder) * except first combo output. */ if (phy == PHY_A) - return GMBUS_PIN_1_BXT; + return GMBUS_PIN_1; - return GMBUS_PIN_9_TC1_ICP + phy - PHY_B; + return GMBUS_PIN_9_TC1 + phy - PHY_B; } static u8 g4x_encoder_to_ddc_pin(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/display/intel_hdmi.h b/drivers/gpu/drm/i915/display/intel_hdmi.h index be2fad57e4ad..0fa3661568e8 100644 --- a/drivers/gpu/drm/i915/display/intel_hdmi.h +++ b/drivers/gpu/drm/i915/display/intel_hdmi.h @@ -70,5 +70,7 @@ void hsw_read_infoframe(struct intel_encoder *encoder, const struct intel_crtc_state *crtc_state, unsigned int type, void *frame, ssize_t len); +void intel_hdmi_poll_for_scrambling_enable(const struct intel_crtc_state *crtc_state, + struct drm_connector *_connector); #endif /* __INTEL_HDMI_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_initial_plane.c b/drivers/gpu/drm/i915/display/intel_initial_plane.c index 6aa253678ec9..e414b5d1085c 100644 --- a/drivers/gpu/drm/i915/display/intel_initial_plane.c +++ b/drivers/gpu/drm/i915/display/intel_initial_plane.c @@ -170,7 +170,7 @@ intel_find_initial_plane_obj(struct intel_crtc *crtc, drm_framebuffer_get(fb); plane_state->uapi.crtc = &crtc->base; - intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc); + intel_plane_copy_uapi_to_hw_state(NULL, plane_state, plane_state, crtc); atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits); diff --git a/drivers/gpu/drm/i915/display/intel_lpe_audio.c b/drivers/gpu/drm/i915/display/intel_lpe_audio.c index 775493306a83..ff2cf479d8e1 100644 --- a/drivers/gpu/drm/i915/display/intel_lpe_audio.c +++ b/drivers/gpu/drm/i915/display/intel_lpe_audio.c @@ -262,10 +262,10 @@ void intel_lpe_audio_irq_handler(struct intel_display *display) if (!HAS_LPE_AUDIO(display)) return; - ret = generic_handle_irq(display->audio.lpe.irq); + ret = generic_handle_irq_safe(display->audio.lpe.irq); if (ret) drm_err_ratelimited(display->drm, - "error handling LPE audio irq: %d\n", ret); + "LPE audio: irq handling failed (%pe)\n", ERR_PTR(ret)); } /** diff --git a/drivers/gpu/drm/i915/display/intel_lt_phy.c b/drivers/gpu/drm/i915/display/intel_lt_phy.c index 615ee980470e..8fc6d230493f 100644 --- a/drivers/gpu/drm/i915/display/intel_lt_phy.c +++ b/drivers/gpu/drm/i915/display/intel_lt_phy.c @@ -1223,11 +1223,7 @@ intel_lt_phy_program_port_clock_ctl(struct intel_encoder *encoder, else val |= XELPDP_DDI_CLOCK_SELECT_PREP(display, XELPDP_DDI_CLOCK_SELECT_MAXPCLK); - /* DP2.0 10G and 20G rates enable MPLLA*/ - if (port_clock == 1000000 || port_clock == 2000000) - val |= XELPDP_SSC_ENABLE_PLLA; - else - val |= ltpll->ssc_enabled ? XELPDP_SSC_ENABLE_PLLB : 0; + val |= ltpll->ssc_enabled ? XELPDP_SSC_ENABLE_PLLA : 0; intel_de_rmw(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port), XELPDP_LANE1_PHY_CLOCK_SELECT | XELPDP_FORWARD_CLOCK_UNGATE | @@ -2178,8 +2174,9 @@ void intel_lt_phy_dump_hw_state(struct drm_printer *p, { int i, j; - drm_printf(p, "lt_phy_pll_hw_state: lane count: %d, ssc enabled: %d, tbt mode: %d\n", - hw_state->lane_count, hw_state->ssc_enabled, hw_state->tbt_mode); + drm_printf(p, "lt_phy_pll_hw_state: lane count: %d, ssc enabled: %s, tbt mode: %s\n", + hw_state->lane_count, str_yes_no(hw_state->ssc_enabled), + str_yes_no(hw_state->tbt_mode)); for (i = 0; i < 3; i++) { drm_printf(p, "config[%d] = 0x%.4x,\n", @@ -2221,6 +2218,14 @@ static bool intel_lt_phy_pll_is_enabled(struct intel_encoder *encoder) XELPDP_LANE_PCLK_PLL_ACK(0); } +static bool readout_ssc_state(struct intel_encoder *encoder) +{ + struct intel_display *display = to_intel_display(encoder); + + return intel_de_read(display, XELPDP_PORT_CLOCK_CTL(display, encoder->port)) & + XELPDP_SSC_ENABLE_PLLA; +} + bool intel_lt_phy_tbt_pll_readout_hw_state(struct intel_display *display, struct intel_dpll *pll, struct intel_dpll_hw_state *hw_state) @@ -2250,6 +2255,7 @@ bool intel_lt_phy_pll_readout_hw_state(struct intel_encoder *encoder, owned_lane_mask = intel_lt_phy_get_owned_lane_mask(encoder); lane = owned_lane_mask & INTEL_LT_PHY_LANE0 ? : INTEL_LT_PHY_LANE1; wakeref = intel_lt_phy_transaction_begin(encoder); + pll_state->ssc_enabled = readout_ssc_state(encoder); pll_state->lane_count = intel_readout_lane_count(encoder, INTEL_LT_PHY_LANE0, INTEL_LT_PHY_LANE1); diff --git a/drivers/gpu/drm/i915/display/intel_lvds.c b/drivers/gpu/drm/i915/display/intel_lvds.c index c8098104d853..872753478cf2 100644 --- a/drivers/gpu/drm/i915/display/intel_lvds.c +++ b/drivers/gpu/drm/i915/display/intel_lvds.c @@ -413,7 +413,8 @@ intel_lvds_mode_valid(struct drm_connector *_connector, return MODE_OK; } -static int intel_lvds_compute_config(struct intel_encoder *encoder, +static int intel_lvds_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *crtc_state, struct drm_connector_state *conn_state) { @@ -459,7 +460,7 @@ static int intel_lvds_compute_config(struct intel_encoder *encoder, * with the panel scaling set up to source from the H/VDisplay * of the original mode. */ - ret = intel_panel_compute_config(connector, adjusted_mode); + ret = intel_panel_compute_config(state, crtc_state, connector); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_panel.c b/drivers/gpu/drm/i915/display/intel_panel.c index 20c548eea6da..81e638d0c7b3 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.c +++ b/drivers/gpu/drm/i915/display/intel_panel.c @@ -67,21 +67,62 @@ static bool is_best_fixed_mode(struct intel_connector *connector, if (!best_mode) return true; - /* - * With VRR always pick a mode with equal/higher than requested - * vrefresh, which we can then reduce to match the requested - * vrefresh by extending the vblank length. - */ - if (intel_vrr_is_in_range(connector, vrefresh) && - intel_vrr_is_in_range(connector, fixed_mode_vrefresh) && - fixed_mode_vrefresh < vrefresh) - return false; - /* pick the fixed_mode that is closest in terms of vrefresh */ return abs(fixed_mode_vrefresh - vrefresh) < abs(drm_mode_vrefresh(best_mode) - vrefresh); } +static bool is_vrr_compatible(const struct drm_display_mode *mode1, + const struct drm_display_mode *mode2) +{ + return drm_mode_match(mode1, mode2, + DRM_MODE_MATCH_CLOCK | + DRM_MODE_MATCH_TIMINGS_VRR | + DRM_MODE_MATCH_FLAGS | + DRM_MODE_MATCH_3D_FLAGS); +} + +static const struct drm_display_mode * +intel_panel_fixed_mode_vrr(struct intel_connector *connector, + const struct drm_display_mode *mode, + const struct drm_display_mode *vrr_ref_mode) +{ + const struct drm_display_mode *fixed_mode, *best_mode = NULL; + int vrefresh = drm_mode_vrefresh(mode); + + if (!intel_vrr_is_in_range(connector, vrefresh)) + return NULL; + + if (vrr_ref_mode && + !intel_vrr_is_in_range(connector, drm_mode_vrefresh(vrr_ref_mode))) + return NULL; + + list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) { + int fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode); + + if (!intel_vrr_is_in_range(connector, fixed_mode_vrefresh)) + continue; + + /* + * With VRR always pick a mode with equal/higher than requested + * vrefresh, which we can then reduce to match the requested + * vrefresh by extending the vblank length. + */ + if (fixed_mode_vrefresh < vrefresh) + continue; + + if (vrr_ref_mode && + !is_vrr_compatible(fixed_mode, vrr_ref_mode)) + continue; + + if (is_best_fixed_mode(connector, vrefresh, + fixed_mode_vrefresh, best_mode)) + best_mode = fixed_mode; + } + + return best_mode; +} + const struct drm_display_mode * intel_panel_fixed_mode(struct intel_connector *connector, const struct drm_display_mode *mode) @@ -197,14 +238,66 @@ enum drrs_type intel_panel_drrs_type(struct intel_connector *connector) return connector->panel.vbt.drrs_type; } -int intel_panel_compute_config(struct intel_connector *connector, - struct drm_display_mode *adjusted_mode) +static int intel_panel_compute_config_vrr(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state, + struct intel_connector *connector) { - const struct drm_display_mode *fixed_mode = - intel_panel_fixed_mode(connector, adjusted_mode); + struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + const struct drm_display_mode *fixed_mode = NULL; int vrefresh, fixed_mode_vrefresh; - bool is_vrr; + /* + * Attempt a VRR based refresh rate change if possible + * when userspace has forbidden a full modeset. + */ + if (!state->base.allow_modeset) { + struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + const struct intel_crtc_state *old_crtc_state = + intel_atomic_get_old_crtc_state(state, crtc); + + if (old_crtc_state->hw.enable && + old_crtc_state->uapi.encoder_mask == crtc_state->uapi.encoder_mask) + fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode, + &old_crtc_state->hw.adjusted_mode); + } + + if (!fixed_mode) + fixed_mode = intel_panel_fixed_mode_vrr(connector, adjusted_mode, NULL); + + if (!fixed_mode) + return -EINVAL; + + vrefresh = drm_mode_vrefresh(adjusted_mode); + fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode); + + drm_mode_copy(adjusted_mode, fixed_mode); + + if (fixed_mode_vrefresh != vrefresh) { + int vsync_start_offset = adjusted_mode->vtotal - adjusted_mode->vsync_start; + int vsync_end_offset = adjusted_mode->vtotal - adjusted_mode->vsync_end; + + adjusted_mode->vtotal = + DIV_ROUND_CLOSEST(adjusted_mode->clock * 1000, + adjusted_mode->htotal * vrefresh); + + adjusted_mode->vsync_start = adjusted_mode->vtotal - vsync_start_offset; + adjusted_mode->vsync_end = adjusted_mode->vtotal - vsync_end_offset; + } + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + return 0; +} + +static int intel_panel_compute_config_fixed_rr(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state, + struct intel_connector *connector) +{ + struct drm_display_mode *adjusted_mode = &crtc_state->hw.adjusted_mode; + const struct drm_display_mode *fixed_mode; + int vrefresh, fixed_mode_vrefresh; + + fixed_mode = intel_panel_fixed_mode(connector, adjusted_mode); if (!fixed_mode) return 0; @@ -212,41 +305,40 @@ int intel_panel_compute_config(struct intel_connector *connector, fixed_mode_vrefresh = drm_mode_vrefresh(fixed_mode); /* - * Assume that we shouldn't muck about with the - * timings if they don't land in the VRR range. + * We don't want to lie too much to the user about the refresh + * rate they're going to get. But we have to allow a bit of latitude + * for Xorg since it likes to automagically cook up modes with slightly + * off refresh rates. */ - is_vrr = intel_vrr_is_in_range(connector, vrefresh) && - intel_vrr_is_in_range(connector, fixed_mode_vrefresh); + if (abs(vrefresh - fixed_mode_vrefresh) > 1) { + drm_dbg_kms(connector->base.dev, + "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n", + connector->base.base.id, connector->base.name, + vrefresh, fixed_mode_vrefresh); - if (!is_vrr) { - /* - * We don't want to lie too much to the user about the refresh - * rate they're going to get. But we have to allow a bit of latitude - * for Xorg since it likes to automagically cook up modes with slightly - * off refresh rates. - */ - if (abs(vrefresh - fixed_mode_vrefresh) > 1) { - drm_dbg_kms(connector->base.dev, - "[CONNECTOR:%d:%s] Requested mode vrefresh (%d Hz) does not match fixed mode vrefresh (%d Hz)\n", - connector->base.base.id, connector->base.name, - vrefresh, fixed_mode_vrefresh); - - return -EINVAL; - } + return -EINVAL; } drm_mode_copy(adjusted_mode, fixed_mode); - if (is_vrr && fixed_mode_vrefresh != vrefresh) - adjusted_mode->vtotal = - DIV_ROUND_CLOSEST(adjusted_mode->clock * 1000, - adjusted_mode->htotal * vrefresh); - drm_mode_set_crtcinfo(adjusted_mode, 0); return 0; } +int intel_panel_compute_config(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state, + struct intel_connector *connector) +{ + int ret; + + ret = intel_panel_compute_config_vrr(state, crtc_state, connector); + if (ret) + ret = intel_panel_compute_config_fixed_rr(state, crtc_state, connector); + + return ret; +} + static void intel_panel_add_edid_alt_fixed_modes(struct intel_connector *connector) { struct intel_display *display = to_intel_display(connector); diff --git a/drivers/gpu/drm/i915/display/intel_panel.h b/drivers/gpu/drm/i915/display/intel_panel.h index 23bd227826c9..30c6078ecb1b 100644 --- a/drivers/gpu/drm/i915/display/intel_panel.h +++ b/drivers/gpu/drm/i915/display/intel_panel.h @@ -14,6 +14,7 @@ struct drm_connector; struct drm_connector_state; struct drm_display_mode; struct drm_edid; +struct intel_atomic_state; struct intel_connector; struct intel_crtc_state; struct intel_display; @@ -45,8 +46,9 @@ enum drm_mode_status intel_panel_mode_valid(struct intel_connector *connector, const struct drm_display_mode *mode, int *target_clock); -int intel_panel_compute_config(struct intel_connector *connector, - struct drm_display_mode *adjusted_mode); +int intel_panel_compute_config(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state, + struct intel_connector *connector); void intel_panel_add_edid_fixed_modes(struct intel_connector *connector, bool use_alt_fixed_modes); void intel_panel_add_vbt_lfp_fixed_mode(struct intel_connector *connector); diff --git a/drivers/gpu/drm/i915/display/intel_parent.c b/drivers/gpu/drm/i915/display/intel_parent.c index a5816561be40..a5e41ea66921 100644 --- a/drivers/gpu/drm/i915/display/intel_parent.c +++ b/drivers/gpu/drm/i915/display/intel_parent.c @@ -251,9 +251,11 @@ struct intel_panic *intel_parent_panic_alloc(struct intel_display *display) return display->parent->panic->alloc(); } -int intel_parent_panic_setup(struct intel_display *display, struct intel_panic *panic, struct drm_scanout_buffer *sb) +int intel_parent_panic_setup(struct intel_display *display, struct intel_panic *panic, + struct drm_scanout_buffer *sb, struct drm_gem_object *obj, + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width)) { - return display->parent->panic->setup(panic, sb); + return display->parent->panic->setup(panic, sb, obj, tiling); } void intel_parent_panic_finish(struct intel_display *display, struct intel_panic *panic) diff --git a/drivers/gpu/drm/i915/display/intel_parent.h b/drivers/gpu/drm/i915/display/intel_parent.h index 27e35f891a6b..595d4148b8eb 100644 --- a/drivers/gpu/drm/i915/display/intel_parent.h +++ b/drivers/gpu/drm/i915/display/intel_parent.h @@ -105,7 +105,9 @@ void intel_parent_overlay_cleanup(struct intel_display *display); /* panic */ struct intel_panic *intel_parent_panic_alloc(struct intel_display *display); -int intel_parent_panic_setup(struct intel_display *display, struct intel_panic *panic, struct drm_scanout_buffer *sb); +int intel_parent_panic_setup(struct intel_display *display, struct intel_panic *panic, + struct drm_scanout_buffer *sb, struct drm_gem_object *obj, + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width)); void intel_parent_panic_finish(struct intel_display *display, struct intel_panic *panic); /* pc8 */ diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index 7017ed6cb9d1..a440f92ff00c 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -408,25 +408,27 @@ intel_plane_colorop_replace_blob(struct intel_plane_state *plane_state, } static void -intel_plane_color_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, +intel_plane_color_copy_uapi_to_hw_state(struct intel_atomic_state *state, + struct intel_plane_state *plane_state, const struct intel_plane_state *from_plane_state, struct intel_crtc *crtc) { struct drm_colorop *iter_colorop, *colorop; struct drm_colorop_state *new_colorop_state; - struct drm_atomic_commit *state = plane_state->uapi.state; struct intel_colorop *intel_colorop; struct drm_property_blob *blob; - struct intel_atomic_state *intel_atomic_state = to_intel_atomic_state(state); - struct intel_crtc_state *new_crtc_state = intel_atomic_state ? - intel_atomic_get_new_crtc_state(intel_atomic_state, crtc) : NULL; + struct intel_crtc_state *new_crtc_state = state ? + intel_atomic_get_new_crtc_state(state, crtc) : NULL; bool changed = false; int i = 0; + if (!state) + return; + iter_colorop = from_plane_state->uapi.color_pipeline; while (iter_colorop) { - for_each_new_colorop_in_state(state, colorop, new_colorop_state, i) { + for_each_new_colorop_in_state(&state->base, colorop, new_colorop_state, i) { if (new_colorop_state->colorop == iter_colorop) { blob = new_colorop_state->bypass ? NULL : new_colorop_state->data; intel_colorop = to_intel_colorop(colorop); @@ -442,7 +444,8 @@ intel_plane_color_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, new_crtc_state->plane_color_changed = true; } -void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, +void intel_plane_copy_uapi_to_hw_state(struct intel_atomic_state *state, + struct intel_plane_state *plane_state, const struct intel_plane_state *from_plane_state, struct intel_crtc *crtc) { @@ -471,19 +474,25 @@ void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, plane_state->uapi.src = drm_plane_state_src(&from_plane_state->uapi); plane_state->uapi.dst = drm_plane_state_dest(&from_plane_state->uapi); - intel_plane_color_copy_uapi_to_hw_state(plane_state, from_plane_state, crtc); + intel_plane_color_copy_uapi_to_hw_state(state, plane_state, from_plane_state, crtc); } -void intel_plane_copy_hw_state(struct intel_plane_state *plane_state, - const struct intel_plane_state *from_plane_state) +static void intel_plane_y_copy_hw_state(struct intel_plane_state *y_plane_state, + const struct intel_plane_state *uv_plane_state) { - intel_plane_clear_hw_state(plane_state); + intel_plane_clear_hw_state(y_plane_state); - memcpy(&plane_state->hw, &from_plane_state->hw, - sizeof(plane_state->hw)); + y_plane_state->hw.crtc = uv_plane_state->hw.crtc; + y_plane_state->hw.fb = uv_plane_state->hw.fb; + if (y_plane_state->hw.fb) + drm_framebuffer_get(y_plane_state->hw.fb); - if (plane_state->hw.fb) - drm_framebuffer_get(plane_state->hw.fb); + y_plane_state->hw.alpha = uv_plane_state->hw.alpha; + y_plane_state->hw.pixel_blend_mode = uv_plane_state->hw.pixel_blend_mode; + y_plane_state->hw.rotation = uv_plane_state->hw.rotation; + y_plane_state->hw.color_encoding = uv_plane_state->hw.color_encoding; + y_plane_state->hw.color_range = uv_plane_state->hw.color_range; + y_plane_state->hw.scaling_filter = uv_plane_state->hw.scaling_filter; } static void unlink_nv12_plane(struct intel_crtc_state *crtc_state, @@ -868,7 +877,8 @@ static int plane_atomic_check(struct intel_atomic_state *state, old_primary_crtc_plane_state, new_primary_crtc_plane_state); - intel_plane_copy_uapi_to_hw_state(new_plane_state, + intel_plane_copy_uapi_to_hw_state(state, + new_plane_state, new_primary_crtc_plane_state, crtc); @@ -1607,17 +1617,17 @@ static int intel_get_scanout_buffer(struct drm_plane *plane, if (fb == intel_fbdev_framebuffer(display->fbdev.fbdev)) { intel_fbdev_get_map(display, &sb->map[0]); } else { + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width) = NULL; int ret; /* Can't disable tiling if DPT is in use */ if (intel_fb_uses_dpt(&fb->base)) { if (fb->base.format->cpp[0] != 4) return -EOPNOTSUPP; - fb->panic_tiling = intel_get_tiling_func(fb->base.modifier); - if (!fb->panic_tiling) + tiling = intel_get_tiling_func(fb->base.modifier); + if (!tiling) return -EOPNOTSUPP; } - sb->private = fb; - ret = intel_parent_panic_setup(display, fb->panic, sb); + ret = intel_parent_panic_setup(display, fb->panic, sb, obj, tiling); if (ret) return ret; } @@ -1688,7 +1698,7 @@ static void link_nv12_planes(struct intel_crtc_state *crtc_state, crtc_state->rel_data_rate[y_plane->id] = crtc_state->rel_data_rate_y[uv_plane->id]; /* Copy parameters to Y plane */ - intel_plane_copy_hw_state(y_plane_state, uv_plane_state); + intel_plane_y_copy_hw_state(y_plane_state, uv_plane_state); y_plane_state->uapi.src = uv_plane_state->uapi.src; y_plane_state->uapi.dst = uv_plane_state->uapi.dst; diff --git a/drivers/gpu/drm/i915/display/intel_plane.h b/drivers/gpu/drm/i915/display/intel_plane.h index a6338bba72d9..31a6229aea73 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.h +++ b/drivers/gpu/drm/i915/display/intel_plane.h @@ -35,11 +35,10 @@ unsigned int intel_plane_pixel_rate(const struct intel_crtc_state *crtc_state, unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state, int color_plane); -void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state, +void intel_plane_copy_uapi_to_hw_state(struct intel_atomic_state *state, + struct intel_plane_state *plane_state, const struct intel_plane_state *from_plane_state, struct intel_crtc *crtc); -void intel_plane_copy_hw_state(struct intel_plane_state *plane_state, - const struct intel_plane_state *from_plane_state); void intel_plane_async_flip(struct intel_dsb *dsb, struct intel_plane *plane, const struct intel_crtc_state *crtc_state, diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c index e138982dc91f..92af21d823a3 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.c +++ b/drivers/gpu/drm/i915/display/intel_psr.c @@ -88,22 +88,6 @@ * issues the self-refresh re-enable code is done from a work queue, which * must be correctly synchronized/cancelled when shutting down the pipe." * - * DC3CO (DC3 clock off) - * - * On top of PSR2, GEN12 adds a intermediate power savings state that turns - * clock off automatically during PSR2 idle state. - * The smaller overhead of DC3co entry/exit vs. the overhead of PSR2 deep sleep - * entry/exit allows the HW to enter a low-power state even when page flipping - * periodically (for instance a 30fps video playback scenario). - * - * Every time a flips occurs PSR2 will get out of deep sleep state(if it was), - * so DC3CO is enabled and tgl_dc3co_disable_work is schedule to run after 6 - * frames, if no other flip occurs and the function above is executed, DC3CO is - * disabled and PSR2 is configured to enter deep sleep, resetting again in case - * of another flip. - * Front buffer modifications do not trigger DC3CO activation on purpose as it - * would bring a lot of complexity and most of the moderns systems will only - * use page flips. */ /* @@ -1098,10 +1082,11 @@ static void hsw_activate_psr2(struct intel_dp *intel_dp) u32 psr_val = 0; u8 idle_frames; - /* Wa_16025596647 */ - if ((DISPLAY_VER(display) == 20 || - IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && - is_dc5_dc6_blocked(intel_dp) && intel_dp->psr.pkg_c_latency_used) + /* DC3CO / Wa_16025596647 */ + if (intel_dp->psr.dc3co_allowed || + ((DISPLAY_VER(display) == 20 || + IS_DISPLAY_VERx100_STEP(display, 3000, STEP_A0, STEP_B0)) && + is_dc5_dc6_blocked(intel_dp) && intel_dp->psr.pkg_c_latency_used)) idle_frames = 0; else idle_frames = psr_compute_idle_frames(intel_dp); @@ -1220,108 +1205,6 @@ static void psr2_program_idle_frames(struct intel_dp *intel_dp, EDP_PSR2_IDLE_FRAMES(idle_frames)); } -static void tgl_psr2_enable_dc3co(struct intel_dp *intel_dp) -{ - struct intel_display *display = to_intel_display(intel_dp); - - psr2_program_idle_frames(intel_dp, 0); - intel_display_power_set_target_dc_state(display, DC_STATE_EN_DC3CO); -} - -static void tgl_psr2_disable_dc3co(struct intel_dp *intel_dp) -{ - struct intel_display *display = to_intel_display(intel_dp); - - intel_display_power_set_target_dc_state(display, DC_STATE_EN_UPTO_DC6); - psr2_program_idle_frames(intel_dp, psr_compute_idle_frames(intel_dp)); -} - -static void tgl_dc3co_disable_work(struct work_struct *work) -{ - struct intel_dp *intel_dp = - container_of(work, typeof(*intel_dp), psr.dc3co_work.work); - - mutex_lock(&intel_dp->psr.lock); - /* If delayed work is pending, it is not idle */ - if (delayed_work_pending(&intel_dp->psr.dc3co_work)) - goto unlock; - - tgl_psr2_disable_dc3co(intel_dp); -unlock: - mutex_unlock(&intel_dp->psr.lock); -} - -static void tgl_disallow_dc3co_on_psr2_exit(struct intel_dp *intel_dp) -{ - if (!intel_dp->psr.dc3co_exitline) - return; - - cancel_delayed_work(&intel_dp->psr.dc3co_work); - /* Before PSR2 exit disallow dc3co*/ - tgl_psr2_disable_dc3co(intel_dp); -} - -static bool -dc3co_is_pipe_port_compatible(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state) -{ - struct intel_display *display = to_intel_display(intel_dp); - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - enum pipe pipe = to_intel_crtc(crtc_state->uapi.crtc)->pipe; - enum port port = dig_port->base.port; - - if (display->platform.alderlake_p || DISPLAY_VER(display) >= 14) - return pipe <= PIPE_B && port <= PORT_B; - else - return pipe == PIPE_A && port == PORT_A; -} - -static void -tgl_dc3co_exitline_compute_config(struct intel_dp *intel_dp, - struct intel_crtc_state *crtc_state) -{ - struct intel_display *display = to_intel_display(intel_dp); - const u32 crtc_vdisplay = crtc_state->uapi.adjusted_mode.crtc_vdisplay; - struct i915_power_domains *power_domains = &display->power.domains; - u32 exit_scanlines; - - /* - * FIXME: Due to the changed sequence of activating/deactivating DC3CO, - * disable DC3CO until the changed dc3co activating/deactivating sequence - * is applied. B.Specs:49196 - */ - return; - - /* - * DMC's DC3CO exit mechanism has an issue with Selective Fecth - * TODO: when the issue is addressed, this restriction should be removed. - */ - if (crtc_state->enable_psr2_sel_fetch) - return; - - if (!(power_domains->allowed_dc_mask & DC_STATE_EN_DC3CO)) - return; - - if (!dc3co_is_pipe_port_compatible(intel_dp, crtc_state)) - return; - - /* Wa_16011303918:adl-p */ - if (intel_display_wa(display, INTEL_DISPLAY_WA_16011303918)) - return; - - /* - * DC3CO Exit time 200us B.Spec 49196 - * PSR2 transcoder Early Exit scanlines = ROUNDUP(200 / line time) + 1 - */ - exit_scanlines = - intel_usecs_to_scanlines(&crtc_state->uapi.adjusted_mode, 200) + 1; - - if (drm_WARN_ON(display->drm, exit_scanlines > crtc_vdisplay)) - return; - - crtc_state->dc3co_exitline = crtc_vdisplay - exit_scanlines; -} - static bool intel_psr2_sel_fetch_config_valid(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) { @@ -1522,9 +1405,6 @@ int _intel_psr_min_set_context_latency(const struct intel_crtc_state *crtc_state needs_panel_replay) return 0; - if (intel_vrr_always_use_vrr_tg(display)) - return 0; - return 1; } @@ -1697,8 +1577,6 @@ static bool intel_psr2_config_valid(struct intel_dp *intel_dp, return false; } - tgl_dc3co_exitline_compute_config(intel_dp, crtc_state); - return true; } @@ -1893,6 +1771,50 @@ static bool intel_psr_needs_wa_18037818876(struct intel_dp *intel_dp, !crtc_state->has_sel_update); } +static void psr2_dc3co_disable_locked(struct intel_dp *intel_dp) +{ + struct intel_display *display = to_intel_display(intel_dp); + + if (intel_dp->psr.dc3co_allowed) { + intel_dp->psr.dc3co_allowed = false; + intel_display_power_set_target_dc_state(display, DC_STATE_EN_UPTO_DC6); + psr2_program_idle_frames(intel_dp, psr_compute_idle_frames(intel_dp)); + } +} + +static void psr2_dc3co_disable_work(struct work_struct *work) +{ + struct intel_dp *intel_dp = + container_of(work, typeof(*intel_dp), psr.dc3co_work.work); + + mutex_lock(&intel_dp->psr.lock); + psr2_dc3co_disable_locked(intel_dp); + mutex_unlock(&intel_dp->psr.lock); +} + +static void +psr2_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits) +{ + struct intel_display *display = to_intel_display(intel_dp); + + if (!intel_dp->psr.dc3co_allowed) + return; + + if (!intel_dp->psr.sel_update_enabled || + !intel_dp->psr.active) + return; + /* + * At every frontbuffer flush flip event modified delay of delayed work, + * when delayed work schedules that means display has been idle. + */ + if (!(frontbuffer_bits & + INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe))) + return; + + mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, + intel_dp->psr.dc3co_exit_delay); +} + static void intel_psr_set_non_psr_pipes(struct intel_dp *intel_dp, struct intel_crtc_state *crtc_state) @@ -2013,12 +1935,6 @@ void intel_psr_get_config(struct intel_encoder *encoder, } pipe_config->enable_psr2_su_region_et = intel_dp->psr.su_region_et_enabled; - - if (DISPLAY_VER(display) >= 12) { - val = intel_de_read(display, - TRANS_EXITLINE(display, cpu_transcoder)); - pipe_config->dc3co_exitline = REG_FIELD_GET(EXITLINE_MASK, val); - } unlock: mutex_unlock(&intel_dp->psr.lock); } @@ -2146,16 +2062,6 @@ static void intel_psr_enable_source(struct intel_dp *intel_dp, psr_irq_control(intel_dp); - /* - * TODO: if future platforms supports DC3CO in more than one - * transcoder, EXITLINE will need to be unset when disabling PSR - */ - if (intel_dp->psr.dc3co_exitline) - intel_de_rmw(display, - TRANS_EXITLINE(display, cpu_transcoder), - EXITLINE_MASK, - intel_dp->psr.dc3co_exitline << EXITLINE_SHIFT | EXITLINE_ENABLE); - if (HAS_PSR_HW_TRACKING(display) && HAS_PSR2_SEL_FETCH(display)) intel_de_rmw(display, CHICKEN_PAR1_1, IGNORE_PSR2_HW_TRACKING, intel_dp->psr.psr2_sel_fetch_enabled ? @@ -2255,7 +2161,6 @@ static void intel_psr_enable_locked(struct intel_dp *intel_dp, /* DC5/DC6 requires at least 6 idle frames */ val = usecs_to_jiffies(intel_get_frame_time_us(crtc_state) * 6); intel_dp->psr.dc3co_exit_delay = val; - intel_dp->psr.dc3co_exitline = crtc_state->dc3co_exitline; intel_dp->psr.psr2_sel_fetch_enabled = crtc_state->enable_psr2_sel_fetch; intel_dp->psr.su_region_et_enabled = crtc_state->enable_psr2_su_region_et; intel_dp->psr.psr2_sel_fetch_cff_enabled = false; @@ -2334,8 +2239,6 @@ static void intel_psr_exit(struct intel_dp *intel_dp) intel_de_rmw(display, TRANS_DP2_CTL(intel_dp->psr.transcoder), TRANS_DP2_PANEL_REPLAY_ENABLE, 0); } else if (intel_dp->psr.sel_update_enabled) { - tgl_disallow_dc3co_on_psr2_exit(intel_dp); - val = intel_de_rmw(display, EDP_PSR2_CTL(display, cpu_transcoder), EDP_PSR2_ENABLE, 0); @@ -2358,6 +2261,27 @@ static void intel_psr_exit(struct intel_dp *intel_dp) intel_dp->psr.active = false; } +bool intel_psr2_in_deep_sleep(struct intel_dp *intel_dp) +{ + struct intel_display *display = to_intel_display(intel_dp); + enum transcoder cpu_transcoder; + bool in_deep_sleep = false; + u32 val; + + mutex_lock(&intel_dp->psr.lock); + + if (!intel_dp->psr.enabled || !intel_dp->psr.sel_update_enabled) + goto out; + + cpu_transcoder = intel_dp->psr.transcoder; + val = intel_de_read(display, EDP_PSR2_STATUS(display, cpu_transcoder)); + in_deep_sleep = (val & EDP_PSR2_STATUS_STATE_MASK) == + EDP_PSR2_STATUS_STATE_DEEP_SLEEP; +out: + mutex_unlock(&intel_dp->psr.lock); + return in_deep_sleep; +} + static void intel_psr_wait_exit_locked(struct intel_dp *intel_dp) { struct intel_display *display = to_intel_display(intel_dp); @@ -2448,6 +2372,8 @@ static void intel_psr_disable_locked(struct intel_dp *intel_dp) intel_dp->psr.psr2_sel_fetch_cff_enabled = false; intel_dp->psr.active_non_psr_pipes = 0; intel_dp->psr.pkg_c_latency_used = 0; + cancel_delayed_work(&intel_dp->psr.dc3co_work); + intel_dp->psr.dc3co_allowed = false; } /** @@ -2535,8 +2461,13 @@ void intel_psr_resume(struct intel_dp *intel_dp) goto out; } - if (--intel_dp->psr.pause_counter == 0) + if (--intel_dp->psr.pause_counter == 0) { intel_psr_activate(intel_dp); + /* re-arm cancelled dc3co work from pause */ + if (intel_dp->psr.dc3co_allowed) + mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, + intel_dp->psr.dc3co_exit_delay); + } out: mutex_unlock(&psr->lock); @@ -3240,10 +3171,13 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, const struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct intel_encoder *encoder; + bool dc3co_allowed; if (!crtc_state->has_psr) return; + dc3co_allowed = intel_display_power_dc3co_allowed(display); + verify_panel_replay_dsc_state(crtc_state); for_each_intel_encoder_mask_with_psr(state->base.dev, encoder, @@ -3271,6 +3205,8 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, keep_disabled = true; } + intel_dp->psr.dc3co_allowed = dc3co_allowed; + if (!psr->enabled && !keep_disabled) intel_psr_enable_locked(intel_dp, crtc_state); else if (psr->enabled && !crtc_state->wm_level_disabled) @@ -3287,6 +3223,11 @@ void intel_psr_post_plane_update(struct intel_atomic_state *state, */ intel_dp->psr.busy_frontbuffer_bits = 0; + if (intel_dp->psr.dc3co_allowed) { + mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, + intel_dp->psr.dc3co_exit_delay); + } + mutex_unlock(&psr->lock); } } @@ -3659,34 +3600,6 @@ void intel_psr_invalidate(struct intel_display *display, mutex_unlock(&intel_dp->psr.lock); } } -/* - * When we will be completely rely on PSR2 S/W tracking in future, - * intel_psr_flush() will invalidate and flush the PSR for ORIGIN_FLIP - * event also therefore tgl_dc3co_flush_locked() require to be changed - * accordingly in future. - */ -static void -tgl_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits, - enum fb_op_origin origin) -{ - struct intel_display *display = to_intel_display(intel_dp); - - if (!intel_dp->psr.dc3co_exitline || !intel_dp->psr.sel_update_enabled || - !intel_dp->psr.active) - return; - - /* - * At every frontbuffer flush flip event modified delay of delayed work, - * when delayed work schedules that means display has been idle. - */ - if (!(frontbuffer_bits & - INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe))) - return; - - tgl_psr2_enable_dc3co(intel_dp); - mod_delayed_work(display->wq.unordered, &intel_dp->psr.dc3co_work, - intel_dp->psr.dc3co_exit_delay); -} static void _psr_flush_handle(struct intel_dp *intel_dp) { @@ -3773,7 +3686,7 @@ void intel_psr_flush(struct intel_display *display, if (origin == ORIGIN_FLIP || (origin == ORIGIN_CURSOR_UPDATE && !intel_dp->psr.psr2_sel_fetch_enabled)) { - tgl_dc3co_flush_locked(intel_dp, frontbuffer_bits, origin); + psr2_dc3co_flush_locked(intel_dp, frontbuffer_bits); goto unlock; } @@ -3832,7 +3745,7 @@ void intel_psr_init(struct intel_dp *intel_dp) intel_dp->psr.link_standby = connector->panel.vbt.psr.full_link; INIT_WORK(&intel_dp->psr.work, intel_psr_work); - INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, tgl_dc3co_disable_work); + INIT_DELAYED_WORK(&intel_dp->psr.dc3co_work, psr2_dc3co_disable_work); mutex_init(&intel_dp->psr.lock); } diff --git a/drivers/gpu/drm/i915/display/intel_psr.h b/drivers/gpu/drm/i915/display/intel_psr.h index 29723e63888f..d545fdaa0de7 100644 --- a/drivers/gpu/drm/i915/display/intel_psr.h +++ b/drivers/gpu/drm/i915/display/intel_psr.h @@ -87,5 +87,6 @@ void intel_psr_compute_config_late(struct intel_dp *intel_dp, int intel_psr_min_guardband(struct intel_crtc_state *crtc_state); bool intel_psr_use_trans_push(const struct intel_crtc_state *crtc_state); bool intel_psr_pr_async_video_timing_supported(struct intel_dp *intel_dp); +bool intel_psr2_in_deep_sleep(struct intel_dp *intel_dp); #endif /* __INTEL_PSR_H__ */ diff --git a/drivers/gpu/drm/i915/display/intel_psr_regs.h b/drivers/gpu/drm/i915/display/intel_psr_regs.h index 8afbf5a38335..16a9e3af198d 100644 --- a/drivers/gpu/drm/i915/display/intel_psr_regs.h +++ b/drivers/gpu/drm/i915/display/intel_psr_regs.h @@ -268,6 +268,7 @@ #define _PR_ALPM_CTL_A 0x60948 #define PR_ALPM_CTL(dev_priv, tran) _MMIO_TRANS2(dev_priv, tran, _PR_ALPM_CTL_A) +#define PR_ALPM_CTL_USE_DC3CO_IDLE_PROTOCOL BIT(7) #define PR_ALPM_CTL_ALLOW_LINK_OFF_BETWEEN_AS_SDP_AND_SU BIT(6) #define PR_ALPM_CTL_RFB_UPDATE_CONTROL BIT(5) #define PR_ALPM_CTL_AS_SDP_TRANSMISSION_IN_ACTIVE_DISABLE BIT(4) diff --git a/drivers/gpu/drm/i915/display/intel_sdvo.c b/drivers/gpu/drm/i915/display/intel_sdvo.c index d83d350959d8..3075ef04df56 100644 --- a/drivers/gpu/drm/i915/display/intel_sdvo.c +++ b/drivers/gpu/drm/i915/display/intel_sdvo.c @@ -1354,7 +1354,8 @@ static bool intel_sdvo_has_audio(struct intel_encoder *encoder, return intel_conn_state->force_audio == HDMI_AUDIO_ON; } -static int intel_sdvo_compute_config(struct intel_encoder *encoder, +static int intel_sdvo_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { @@ -1398,8 +1399,8 @@ static int intel_sdvo_compute_config(struct intel_encoder *encoder, const struct drm_display_mode *fixed_mode; int ret; - ret = intel_panel_compute_config(&intel_sdvo_connector->base, - adjusted_mode); + ret = intel_panel_compute_config(state, pipe_config, + &intel_sdvo_connector->base); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/display/intel_tv.c b/drivers/gpu/drm/i915/display/intel_tv.c index 0a926c6f25f4..840e1dcdc2d0 100644 --- a/drivers/gpu/drm/i915/display/intel_tv.c +++ b/drivers/gpu/drm/i915/display/intel_tv.c @@ -1187,13 +1187,12 @@ static bool intel_tv_vert_scaling(const struct drm_display_mode *tv_mode, } static int -intel_tv_compute_config(struct intel_encoder *encoder, +intel_tv_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { struct intel_display *display = to_intel_display(encoder); - struct intel_atomic_state *state = - to_intel_atomic_state(pipe_config->uapi.state); struct intel_crtc *crtc = to_intel_crtc(pipe_config->uapi.crtc); struct intel_tv_connector_state *tv_conn_state = to_intel_tv_connector_state(conn_state); diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c index e03b5daac5be..bffbdee76ee1 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.c +++ b/drivers/gpu/drm/i915/display/intel_vrr.c @@ -7,8 +7,10 @@ #include #include "intel_alpm.h" +#include "intel_cmtg.h" #include "intel_crtc.h" #include "intel_de.h" +#include "intel_display_limits.h" #include "intel_display_regs.h" #include "intel_display_types.h" #include "intel_dmc.h" @@ -74,6 +76,10 @@ bool intel_vrr_is_capable(struct intel_connector *connector) return false; } + if (!info->monitor_range.min_vfreq || !info->monitor_range.max_vfreq || + info->monitor_range.min_vfreq > info->monitor_range.max_vfreq) + return false; + return info->monitor_range.max_vfreq - info->monitor_range.min_vfreq > 10; } @@ -318,19 +324,19 @@ int intel_vrr_fixed_rr_hw_flipline(const struct intel_crtc_state *crtc_state) return intel_vrr_fixed_rr_hw_vtotal(crtc_state); } -void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state) +void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state, + enum transcoder transcoder) { struct intel_display *display = to_intel_display(crtc_state); - enum transcoder cpu_transcoder = crtc_state->cpu_transcoder; if (!intel_vrr_possible(crtc_state)) return; - intel_de_write(display, TRANS_VRR_VMIN(display, cpu_transcoder), + intel_de_write(display, TRANS_VRR_VMIN(display, transcoder), intel_vrr_fixed_rr_hw_vmin(crtc_state) - 1); - intel_de_write(display, TRANS_VRR_VMAX(display, cpu_transcoder), + intel_de_write(display, TRANS_VRR_VMAX(display, transcoder), intel_vrr_fixed_rr_hw_vmax(crtc_state) - 1); - intel_de_write(display, TRANS_VRR_FLIPLINE(display, cpu_transcoder), + intel_de_write(display, TRANS_VRR_FLIPLINE(display, transcoder), intel_vrr_fixed_rr_hw_flipline(crtc_state) - 1); } @@ -645,7 +651,8 @@ void intel_vrr_set_transcoder_timings(const struct intel_crtc_state *crtc_state) lower_32_bits(crtc_state->cmrr.cmrr_n)); } - intel_vrr_set_fixed_rr_timings(crtc_state); + intel_vrr_set_fixed_rr_timings(crtc_state, cpu_transcoder); + intel_cmtg_set_vrr_timings(crtc_state); if (!intel_vrr_always_use_vrr_tg(display)) intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), @@ -930,6 +937,8 @@ static void intel_vrr_tg_enable(const struct intel_crtc_state *crtc_state, vrr_ctl |= VRR_CTL_CMRR_ENABLE; intel_de_write(display, TRANS_VRR_CTL(display, cpu_transcoder), vrr_ctl); + + intel_cmtg_set_vrr_ctl(crtc_state); } static void intel_vrr_tg_disable(const struct intel_crtc_state *old_crtc_state) @@ -974,7 +983,7 @@ void intel_vrr_disable(const struct intel_crtc_state *old_crtc_state) intel_vrr_tg_disable(old_crtc_state); intel_vrr_disable_dc_balancing(old_crtc_state); - intel_vrr_set_fixed_rr_timings(old_crtc_state); + intel_vrr_set_fixed_rr_timings(old_crtc_state, old_crtc_state->cpu_transcoder); } void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state) @@ -1097,16 +1106,6 @@ void intel_vrr_get_config(struct intel_crtc_state *crtc_state) crtc_state->vrr.vmin += intel_vrr_vmin_flipline_offset(display); } - /* - * For platforms that always use VRR Timing Generator, the VTOTAL.Vtotal - * bits are not filled. Since for these platforms TRAN_VMIN is always - * filled with crtc_vtotal, use TRAN_VRR_VMIN to get the vtotal for - * adjusted_mode. - */ - if (intel_vrr_always_use_vrr_tg(display)) - crtc_state->hw.adjusted_mode.crtc_vtotal = - intel_vrr_vmin_vtotal(crtc_state); - if (HAS_AS_SDP(display)) { trans_vrr_vsync = intel_de_read(display, diff --git a/drivers/gpu/drm/i915/display/intel_vrr.h b/drivers/gpu/drm/i915/display/intel_vrr.h index 4f16ca4af91f..55e9c429f579 100644 --- a/drivers/gpu/drm/i915/display/intel_vrr.h +++ b/drivers/gpu/drm/i915/display/intel_vrr.h @@ -15,6 +15,7 @@ struct intel_crtc; struct intel_crtc_state; struct intel_dsb; struct intel_display; +enum transcoder; bool intel_vrr_is_capable(struct intel_connector *connector); bool intel_vrr_is_in_range(struct intel_connector *connector, int vrefresh); @@ -42,7 +43,8 @@ int intel_vrr_vmin_vblank_start(const struct intel_crtc_state *crtc_state); bool intel_vrr_is_fixed_rr(const struct intel_crtc_state *crtc_state); void intel_vrr_transcoder_enable(const struct intel_crtc_state *crtc_state); void intel_vrr_transcoder_disable(const struct intel_crtc_state *crtc_state); -void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state); +void intel_vrr_set_fixed_rr_timings(const struct intel_crtc_state *crtc_state, + enum transcoder transcoder); void intel_vrr_dcb_reset(const struct intel_crtc_state *old_crtc_state, struct intel_crtc *crtc); bool intel_vrr_always_use_vrr_tg(struct intel_display *display); diff --git a/drivers/gpu/drm/i915/display/vlv_dsi.c b/drivers/gpu/drm/i915/display/vlv_dsi.c index 877eab75f19a..8829f365592e 100644 --- a/drivers/gpu/drm/i915/display/vlv_dsi.c +++ b/drivers/gpu/drm/i915/display/vlv_dsi.c @@ -266,7 +266,8 @@ static void band_gap_reset(struct intel_display *display) vlv_flisdsi_put(display); } -static int intel_dsi_compute_config(struct intel_encoder *encoder, +static int intel_dsi_compute_config(struct intel_atomic_state *state, + struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { @@ -280,7 +281,7 @@ static int intel_dsi_compute_config(struct intel_encoder *encoder, pipe_config->sink_format = INTEL_OUTPUT_FORMAT_RGB; pipe_config->output_format = INTEL_OUTPUT_FORMAT_RGB; - ret = intel_panel_compute_config(intel_connector, adjusted_mode); + ret = intel_panel_compute_config(state, pipe_config, intel_connector); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.h b/drivers/gpu/drm/i915/gem/i915_gem_object.h index 8878539c10ed..2c5d20e4dbaf 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_object.h +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.h @@ -17,8 +17,6 @@ #include "i915_vma_types.h" enum intel_region_id; -struct drm_scanout_buffer; -struct intel_panic; #define obj_to_i915(obj__) to_i915((obj__)->base.dev) @@ -693,11 +691,6 @@ i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj); int i915_gem_object_truncate(struct drm_i915_gem_object *obj); -struct intel_panic *i915_gem_object_alloc_panic(void); -int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb, - struct drm_gem_object *_obj, bool panic_tiling); -void i915_gem_object_panic_finish(struct intel_panic *panic); - /** * i915_gem_object_pin_map - return a contiguous mapping of the entire object * @obj: the object to map into kernel address space diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c index df35bdb755e4..59e3d4de7d3c 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c @@ -6,11 +6,8 @@ #include #include -#include #include -#include "display/intel_fb.h" -#include "display/intel_display_types.h" #include "gt/intel_gt.h" #include "gt/intel_tlb.h" @@ -359,131 +356,6 @@ static void *i915_gem_object_map_pfn(struct drm_i915_gem_object *obj, return vaddr ?: ERR_PTR(-ENOMEM); } -struct intel_panic { - struct page **pages; - int page; - void *vaddr; -}; - -static void i915_panic_kunmap(struct intel_panic *panic) -{ - if (panic->vaddr) { - drm_clflush_virt_range(panic->vaddr, PAGE_SIZE); - kunmap_local(panic->vaddr); - panic->vaddr = NULL; - } -} - -static struct page **i915_gem_object_panic_pages(struct drm_i915_gem_object *obj) -{ - unsigned long n_pages = obj->base.size >> PAGE_SHIFT, i; - struct page *page; - struct page **pages; - struct sgt_iter iter; - - /* For a 3840x2160 32 bits Framebuffer, this should require ~64K */ - pages = kmalloc_objs(*pages, n_pages, GFP_ATOMIC); - if (!pages) - return NULL; - - i = 0; - for_each_sgt_page(page, iter, obj->mm.pages) - pages[i++] = page; - return pages; -} - -static void i915_gem_object_panic_map_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, - unsigned int y, u32 color) -{ - struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private; - unsigned int offset = fb->panic_tiling(sb->width, x, y); - - iosys_map_wr(&sb->map[0], offset, u32, color); -} - -/* - * The scanout buffer pages are not mapped, so for each pixel, - * use kmap_local_page_try_from_panic() to map the page, and write the pixel. - * Try to keep the map from the previous pixel, to avoid too much map/unmap. - */ -static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, - unsigned int y, u32 color) -{ - unsigned int new_page; - unsigned int offset; - struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private; - struct intel_panic *panic = fb->panic; - - if (fb->panic_tiling) - offset = fb->panic_tiling(sb->width, x, y); - else - offset = y * sb->pitch[0] + x * sb->format->cpp[0]; - - new_page = offset >> PAGE_SHIFT; - offset = offset % PAGE_SIZE; - if (new_page != panic->page) { - i915_panic_kunmap(panic); - panic->page = new_page; - panic->vaddr = - kmap_local_page_try_from_panic(panic->pages[panic->page]); - } - if (panic->vaddr) { - u32 *pix = panic->vaddr + offset; - *pix = color; - } -} - -struct intel_panic *i915_gem_object_alloc_panic(void) -{ - struct intel_panic *panic; - - panic = kzalloc_obj(*panic); - - return panic; -} - -/* - * Setup the gem framebuffer for drm_panic access. - * Use current vaddr if it exists, or setup a list of pages. - * pfn is not supported yet. - */ -int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb, - struct drm_gem_object *_obj, bool panic_tiling) -{ - enum i915_map_type has_type; - struct drm_i915_gem_object *obj = to_intel_bo(_obj); - void *ptr; - - ptr = page_unpack_bits(obj->mm.mapping, &has_type); - if (ptr) { - if (i915_gem_object_has_iomem(obj)) - iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)ptr); - else - iosys_map_set_vaddr(&sb->map[0], ptr); - - if (panic_tiling) - sb->set_pixel = i915_gem_object_panic_map_set_pixel; - return 0; - } - if (i915_gem_object_has_struct_page(obj)) { - panic->pages = i915_gem_object_panic_pages(obj); - if (!panic->pages) - return -ENOMEM; - panic->page = -1; - sb->set_pixel = i915_gem_object_panic_page_set_pixel; - return 0; - } - return -EOPNOTSUPP; -} - -void i915_gem_object_panic_finish(struct intel_panic *panic) -{ - i915_panic_kunmap(panic); - panic->page = -1; - kfree(panic->pages); - panic->pages = NULL; -} - /* get, pin, and map the pages of the object into kernel space */ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, enum i915_map_type type) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_panic.c b/drivers/gpu/drm/i915/gem/i915_gem_panic.c new file mode 100644 index 000000000000..91389d36f101 --- /dev/null +++ b/drivers/gpu/drm/i915/gem/i915_gem_panic.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: MIT +/* Copyright © 2026 Intel Corporation */ + +#include +#include +#include + +#include "i915_gem_object.h" +#include "i915_gem_panic.h" + +struct intel_panic { + struct page **pages; + int page; + void *vaddr; + + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width); +}; + +static void i915_panic_kunmap(struct intel_panic *panic) +{ + if (panic->vaddr) { + drm_clflush_virt_range(panic->vaddr, PAGE_SIZE); + kunmap_local(panic->vaddr); + panic->vaddr = NULL; + } +} + +static struct page **i915_gem_object_panic_pages(struct drm_i915_gem_object *obj) +{ + unsigned long n_pages = obj->base.size >> PAGE_SHIFT, i; + struct page *page; + struct page **pages; + struct sgt_iter iter; + + /* For a 3840x2160 32 bits Framebuffer, this should require ~64K */ + pages = kmalloc_objs(*pages, n_pages, GFP_ATOMIC); + if (!pages) + return NULL; + + i = 0; + for_each_sgt_page(page, iter, obj->mm.pages) + pages[i++] = page; + return pages; +} + +static void i915_gem_object_panic_map_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, + unsigned int y, u32 color) +{ + struct intel_panic *panic = sb->private; + unsigned int offset = panic->tiling(sb->width, x, y); + + iosys_map_wr(&sb->map[0], offset, u32, color); +} + +/* + * The scanout buffer pages are not mapped, so for each pixel, + * use kmap_local_page_try_from_panic() to map the page, and write the pixel. + * Try to keep the map from the previous pixel, to avoid too much map/unmap. + */ +static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, + unsigned int y, u32 color) +{ + struct intel_panic *panic = sb->private; + unsigned int new_page; + unsigned int offset; + + if (panic->tiling) + offset = panic->tiling(sb->width, x, y); + else + offset = y * sb->pitch[0] + x * sb->format->cpp[0]; + + new_page = offset >> PAGE_SHIFT; + offset = offset % PAGE_SIZE; + if (new_page != panic->page) { + i915_panic_kunmap(panic); + panic->page = new_page; + panic->vaddr = + kmap_local_page_try_from_panic(panic->pages[panic->page]); + } + if (panic->vaddr) { + u32 *pix = panic->vaddr + offset; + *pix = color; + } +} + +static struct intel_panic *i915_gem_object_alloc_panic(void) +{ + struct intel_panic *panic; + + panic = kzalloc_obj(*panic); + + return panic; +} + +/* + * Setup the gem framebuffer for drm_panic access. + * Use current vaddr if it exists, or setup a list of pages. + * pfn is not supported yet. + */ +static int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb, + struct drm_gem_object *_obj, + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width)) +{ + enum i915_map_type has_type; + struct drm_i915_gem_object *obj = to_intel_bo(_obj); + void *ptr; + + sb->private = panic; + + ptr = page_unpack_bits(obj->mm.mapping, &has_type); + if (ptr) { + if (i915_gem_object_has_iomem(obj)) + iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)ptr); + else + iosys_map_set_vaddr(&sb->map[0], ptr); + + if (tiling) { + panic->tiling = tiling; + sb->set_pixel = i915_gem_object_panic_map_set_pixel; + } + return 0; + } + if (i915_gem_object_has_struct_page(obj)) { + panic->pages = i915_gem_object_panic_pages(obj); + if (!panic->pages) + return -ENOMEM; + panic->page = -1; + panic->tiling = tiling; + sb->set_pixel = i915_gem_object_panic_page_set_pixel; + return 0; + } + return -EOPNOTSUPP; +} + +static void i915_gem_object_panic_finish(struct intel_panic *panic) +{ + i915_panic_kunmap(panic); + panic->page = -1; + kfree(panic->pages); + panic->pages = NULL; +} + +const struct intel_display_panic_interface i915_display_panic_interface = { + .alloc = i915_gem_object_alloc_panic, + .setup = i915_gem_object_panic_setup, + .finish = i915_gem_object_panic_finish, +}; diff --git a/drivers/gpu/drm/i915/gem/i915_gem_panic.h b/drivers/gpu/drm/i915/gem/i915_gem_panic.h new file mode 100644 index 000000000000..82c3aca6f1f3 --- /dev/null +++ b/drivers/gpu/drm/i915/gem/i915_gem_panic.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright © 2026 Intel Corporation */ + +#ifndef __I915_GEM_PANIC_H__ +#define __I915_GEM_PANIC_H__ + +#include + +extern const struct intel_display_panic_interface i915_display_panic_interface; + +#endif /* __I915_GEM_PANIC_H__ */ diff --git a/drivers/gpu/drm/i915/gt/intel_gsc.c b/drivers/gpu/drm/i915/gt/intel_gsc.c index 050d909fb4f8..1c06bf76568a 100644 --- a/drivers/gpu/drm/i915/gt/intel_gsc.c +++ b/drivers/gpu/drm/i915/gt/intel_gsc.c @@ -286,7 +286,7 @@ static void gsc_irq_handler(struct intel_gt *gt, unsigned int intf_id) ret = generic_handle_irq_safe(gt->gsc.intf[intf_id].irq); if (ret) - gt_err_ratelimited(gt, "error handling GSC irq: %d\n", ret); + gt_err_ratelimited(gt, "GSC: irq handling failed (%pe)\n", ERR_PTR(ret)); } void intel_gsc_irq_handler(struct intel_gt *gt, u32 iir) diff --git a/drivers/gpu/drm/i915/gvt/edid.c b/drivers/gpu/drm/i915/gvt/edid.c index ca5b54466a65..dc9ef98ff51b 100644 --- a/drivers/gpu/drm/i915/gvt/edid.c +++ b/drivers/gpu/drm/i915/gvt/edid.c @@ -90,13 +90,13 @@ static inline int cnp_get_port_from_gmbus0(u32 gmbus0) int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK; int port = -EINVAL; - if (port_select == GMBUS_PIN_1_BXT) + if (port_select == GMBUS_PIN_1) port = PORT_B; - else if (port_select == GMBUS_PIN_2_BXT) + else if (port_select == GMBUS_PIN_2) port = PORT_C; - else if (port_select == GMBUS_PIN_3_BXT) + else if (port_select == GMBUS_PIN_3) port = PORT_D; - else if (port_select == GMBUS_PIN_4_CNP) + else if (port_select == GMBUS_PIN_4) port = PORT_E; return port; } @@ -106,11 +106,11 @@ static inline int bxt_get_port_from_gmbus0(u32 gmbus0) int port_select = gmbus0 & _GMBUS_PIN_SEL_MASK; int port = -EINVAL; - if (port_select == GMBUS_PIN_1_BXT) + if (port_select == GMBUS_PIN_1) port = PORT_B; - else if (port_select == GMBUS_PIN_2_BXT) + else if (port_select == GMBUS_PIN_2) port = PORT_C; - else if (port_select == GMBUS_PIN_3_BXT) + else if (port_select == GMBUS_PIN_3) port = PORT_D; return port; } diff --git a/drivers/gpu/drm/i915/i915_active.c b/drivers/gpu/drm/i915/i915_active.c index e7632c1ff4be..b2442f05825e 100644 --- a/drivers/gpu/drm/i915/i915_active.c +++ b/drivers/gpu/drm/i915/i915_active.c @@ -318,7 +318,7 @@ active_instance(struct i915_active *ref, u64 idx) */ node = kmem_cache_alloc(slab_cache, GFP_ATOMIC); if (!node) - goto out; + goto err; __i915_active_fence_init(&node->base, NULL, node_retire); node->ref = ref; @@ -332,6 +332,11 @@ active_instance(struct i915_active *ref, u64 idx) spin_unlock_irq(&ref->tree_lock); return &node->base; + +err: + spin_unlock_irq(&ref->tree_lock); + + return NULL; } void __i915_active_init(struct i915_active *ref, diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index 58081b52461a..45f2dcc5130e 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -51,7 +51,6 @@ #include #include "display/i9xx_display_sr.h" -#include "display/intel_bw.h" #include "display/intel_cdclk.h" #include "display/intel_crtc.h" #include "display/intel_display_device.h" @@ -60,8 +59,6 @@ #include "display/intel_dmc.h" #include "display/intel_dp.h" #include "display/intel_dpt.h" -#include "display/intel_dram.h" -#include "display/intel_encoder.h" #include "display/intel_fbdev.h" #include "display/intel_gmbus.h" #include "display/intel_hotplug.h" @@ -79,6 +76,7 @@ #include "gem/i915_gem_ioctls.h" #include "gem/i915_gem_mman.h" #include "gem/i915_gem_object_frontbuffer.h" +#include "gem/i915_gem_panic.h" #include "gem/i915_gem_pm.h" #include "gt/intel_gt.h" #include "gt/intel_gt_pm.h" @@ -111,7 +109,6 @@ #include "i915_irq.h" #include "i915_memcpy.h" #include "i915_overlay.h" -#include "i915_panic.h" #include "i915_perf.h" #include "i915_query.h" #include "i915_reg.h" @@ -470,7 +467,6 @@ static int i915_pcode_init(struct drm_i915_private *i915) */ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) { - struct intel_display *display = dev_priv->display; struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); int ret; @@ -564,28 +560,14 @@ static int i915_driver_hw_probe(struct drm_i915_private *dev_priv) drm_dbg(&dev_priv->drm, "can't enable MSI"); } - intel_opregion_setup(display); - ret = i915_pcode_init(dev_priv); if (ret) - goto err_opregion; - - /* - * Fill the dram structure to get the system dram info. This will be - * used for memory latency calculation. - */ - ret = intel_dram_detect(display); - if (ret) - goto err_opregion; - - intel_bw_init_hw(display); + goto err_msi; return 0; -err_opregion: - intel_opregion_cleanup(display); - if (pdev->msi_enabled) - pci_disable_msi(pdev); +err_msi: + pci_disable_msi(pdev); err_mem_regions: intel_memory_regions_driver_release(dev_priv); err_ggtt: @@ -604,15 +586,11 @@ ALLOW_ERROR_INJECTION(i915_driver_hw_probe, ERRNO); */ static void i915_driver_hw_remove(struct drm_i915_private *dev_priv) { - struct intel_display *display = dev_priv->display; struct pci_dev *pdev = to_pci_dev(dev_priv->drm.dev); i915_perf_fini(dev_priv); - intel_opregion_cleanup(display); - - if (pdev->msi_enabled) - pci_disable_msi(pdev); + pci_disable_msi(pdev); } /** @@ -803,7 +781,6 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) const struct intel_device_info *match_info = (struct intel_device_info *)ent->driver_data; struct drm_i915_private *i915; - struct intel_display *display; i915 = devm_drm_dev_alloc(&pdev->dev, &i915_drm_driver, struct drm_i915_private, drm); @@ -818,12 +795,6 @@ i915_driver_create(struct pci_dev *pdev, const struct pci_device_id *ent) /* Set up device info and initial runtime info. */ intel_device_info_driver_create(i915, pdev->device, match_info); - display = intel_display_device_probe(pdev, &parent); - if (IS_ERR(display)) - return ERR_CAST(display); - - i915->display = display; - return i915; } @@ -856,7 +827,13 @@ int i915_driver_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return PTR_ERR(i915); } - display = i915->display; + display = intel_display_device_probe(pdev, &parent); + if (IS_ERR(display)) { + ret = PTR_ERR(display); + goto out_pci_disable; + } + + i915->display = display; ret = i915_driver_early_probe(i915); if (ret < 0) @@ -971,7 +948,6 @@ void i915_driver_remove(struct drm_i915_private *i915) intel_display_driver_remove(display); intel_irq_uninstall(i915); - intel_hpd_cancel_work(display); intel_display_driver_remove_noirq(display); @@ -1043,43 +1019,24 @@ void i915_driver_shutdown(struct drm_i915_private *i915) disable_rpm_wakeref_asserts(&i915->runtime_pm); intel_runtime_pm_disable(&i915->runtime_pm); - intel_display_power_disable(display); - drm_client_dev_suspend(&i915->drm); - if (intel_display_device_present(display)) { - drm_kms_helper_poll_disable(&i915->drm); - intel_display_driver_disable_user_access(display); - - drm_atomic_helper_shutdown(&i915->drm); - } - - intel_dp_mst_suspend(display); + intel_display_driver_shutdown(display); intel_irq_suspend(i915); - intel_hpd_cancel_work(display); - - if (intel_display_device_present(display)) - intel_display_driver_suspend_access(display); - - intel_encoder_suspend_all(display); - intel_encoder_shutdown_all(display); intel_dmc_suspend(display); i915_gem_suspend(i915); /* - * The only requirement is to reboot with display DC states disabled, - * for now leaving all display power wells in the INIT power domain - * enabled. - * * TODO: * - unify the pci_driver::shutdown sequence here with the * pci_driver.driver.pm.poweroff,poweroff_late sequence. * - unify the driver remove and system/runtime suspend sequences with * the above unified shutdown/poweroff sequence. */ - intel_display_power_driver_remove(display); + + intel_display_driver_shutdown_late(display); enable_rpm_wakeref_asserts(&i915->runtime_pm); intel_runtime_pm_driver_last_release(&i915->runtime_pm); @@ -1108,10 +1065,10 @@ static int i915_drm_prepare(struct drm_device *dev) intel_pxp_suspend_prepare(i915->pxp); /* - * NB intel_display_driver_suspend() may issue new requests after we've - * ostensibly marked the GPU as ready-to-sleep here. We need to - * split out that work and pull it forward so that after point, - * the GPU is not woken again. + * NB intel_display_driver_pm_suspend() may issue new requests after + * we've ostensibly marked the GPU as ready-to-sleep here. We need to + * split out that work and pull it forward so that after point, the GPU + * is not woken again. */ return i915_gem_backup_suspend(i915); } @@ -1124,24 +1081,9 @@ static int i915_drm_suspend(struct drm_device *dev) disable_rpm_wakeref_asserts(&dev_priv->runtime_pm); - /* We do a lot of poking in a lot of registers, make sure they work - * properly. */ - intel_display_power_disable(display); - drm_client_dev_suspend(dev); - if (intel_display_device_present(display)) { - drm_kms_helper_poll_disable(dev); - intel_display_driver_disable_user_access(display); - } - - intel_display_driver_suspend(display); + intel_display_driver_pm_suspend(display); intel_irq_suspend(dev_priv); - intel_hpd_cancel_work(display); - - if (intel_display_device_present(display)) - intel_display_driver_suspend_access(display); - - intel_encoder_suspend_all(display); /* Must be called before GGTT is suspended. */ intel_dpt_suspend(display); @@ -1181,12 +1123,12 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation) for_each_gt(gt, dev_priv, i) intel_uncore_suspend(gt->uncore); - intel_display_power_suspend_late(display, s2idle); + intel_display_driver_pm_suspend_late(display, s2idle); ret = vlv_suspend_complete(dev_priv); if (ret) { drm_err(&dev_priv->drm, "Suspend complete failed: %d\n", ret); - intel_display_power_resume_early(display); + intel_display_driver_pm_resume_early(display); } enable_rpm_wakeref_asserts(rpm); @@ -1309,24 +1251,7 @@ static int i915_drm_resume(struct drm_device *dev) intel_clock_gating_init(&dev_priv->drm); - if (intel_display_device_present(display)) - intel_display_driver_resume_access(display); - - intel_hpd_init(display); - - intel_display_driver_resume(display); - - if (intel_display_device_present(display)) { - intel_display_driver_enable_user_access(display); - drm_kms_helper_poll_enable(dev); - } - intel_hpd_poll_disable(display); - - intel_opregion_resume(display); - - drm_client_dev_resume(dev); - - intel_display_power_enable(display); + intel_display_driver_pm_resume(display); intel_gvt_resume(dev_priv); @@ -1362,7 +1287,7 @@ static int i915_drm_resume_early(struct drm_device *dev) for_each_gt(gt, dev_priv, i) intel_gt_resume_early(gt); - intel_display_power_resume_early(display); + intel_display_driver_pm_resume_early(display); enable_rpm_wakeref_asserts(&dev_priv->runtime_pm); diff --git a/drivers/gpu/drm/i915/i915_panic.c b/drivers/gpu/drm/i915/i915_panic.c deleted file mode 100644 index 728be077e8e8..000000000000 --- a/drivers/gpu/drm/i915/i915_panic.c +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: MIT -/* Copyright © 2025 Intel Corporation */ - -#include -#include - -#include "display/intel_display_types.h" -#include "display/intel_fb.h" -#include "gem/i915_gem_object.h" - -#include "i915_panic.h" - -static struct intel_panic *intel_panic_alloc(void) -{ - return i915_gem_object_alloc_panic(); -} - -static int intel_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb) -{ - struct intel_framebuffer *fb = sb->private; - struct drm_gem_object *obj = intel_fb_bo(&fb->base); - - return i915_gem_object_panic_setup(panic, sb, obj, fb->panic_tiling); -} - -static void intel_panic_finish(struct intel_panic *panic) -{ - return i915_gem_object_panic_finish(panic); -} - -const struct intel_display_panic_interface i915_display_panic_interface = { - .alloc = intel_panic_alloc, - .setup = intel_panic_setup, - .finish = intel_panic_finish, -}; diff --git a/drivers/gpu/drm/i915/i915_panic.h b/drivers/gpu/drm/i915/i915_panic.h deleted file mode 100644 index 743d8c861c42..000000000000 --- a/drivers/gpu/drm/i915/i915_panic.h +++ /dev/null @@ -1,9 +0,0 @@ -/* SPDX-License-Identifier: MIT */ -/* Copyright © 2025 Intel Corporation */ - -#ifndef __I915_PANIC_H__ -#define __I915_PANIC_H__ - -extern const struct intel_display_panic_interface i915_display_panic_interface; - -#endif /* __I915_PANIC_H__ */ diff --git a/drivers/gpu/drm/imagination/pvr_context.c b/drivers/gpu/drm/imagination/pvr_context.c index eba4694400b5..52e16c1e7af0 100644 --- a/drivers/gpu/drm/imagination/pvr_context.c +++ b/drivers/gpu/drm/imagination/pvr_context.c @@ -161,22 +161,24 @@ ctx_fw_data_init(void *cpu_ptr, void *priv) /** * pvr_context_destroy_queues() - Destroy all queues attached to a context. * @ctx: Context to destroy queues on. + * @cleanup_queue_entity: Whether to cleanup the queue entity e.g. context + * creation failure path. * * Should be called when the last reference to a context object is dropped. * It releases all resources attached to the queues bound to this context. */ -static void pvr_context_destroy_queues(struct pvr_context *ctx) +static void pvr_context_destroy_queues(struct pvr_context *ctx, bool cleanup_queue_entity) { switch (ctx->type) { case DRM_PVR_CTX_TYPE_RENDER: - pvr_queue_destroy(ctx->queues.fragment); - pvr_queue_destroy(ctx->queues.geometry); + pvr_queue_destroy(ctx->queues.fragment, cleanup_queue_entity); + pvr_queue_destroy(ctx->queues.geometry, cleanup_queue_entity); break; case DRM_PVR_CTX_TYPE_COMPUTE: - pvr_queue_destroy(ctx->queues.compute); + pvr_queue_destroy(ctx->queues.compute, cleanup_queue_entity); break; case DRM_PVR_CTX_TYPE_TRANSFER_FRAG: - pvr_queue_destroy(ctx->queues.transfer); + pvr_queue_destroy(ctx->queues.transfer, cleanup_queue_entity); break; } } @@ -240,7 +242,7 @@ static int pvr_context_create_queues(struct pvr_context *ctx, return -EINVAL; err_destroy_queues: - pvr_context_destroy_queues(ctx); + pvr_context_destroy_queues(ctx, true); return err; } @@ -349,7 +351,7 @@ int pvr_context_create(struct pvr_file *pvr_file, struct drm_pvr_ioctl_create_co pvr_fw_object_destroy(ctx->fw_obj); err_destroy_queues: - pvr_context_destroy_queues(ctx); + pvr_context_destroy_queues(ctx, true); err_free_ctx_id: /* @@ -384,7 +386,7 @@ pvr_context_release(struct kref *ref_count) spin_unlock(&pvr_dev->ctx_list_lock); xa_erase(&pvr_dev->ctx_ids, ctx->ctx_id); - pvr_context_destroy_queues(ctx); + pvr_context_destroy_queues(ctx, false); pvr_fw_object_destroy(ctx->fw_obj); kfree(ctx->data); pvr_vm_context_put(ctx->vm_ctx); diff --git a/drivers/gpu/drm/imagination/pvr_drv.c b/drivers/gpu/drm/imagination/pvr_drv.c index ca3042d14253..8897b3bdeb4a 100644 --- a/drivers/gpu/drm/imagination/pvr_drv.c +++ b/drivers/gpu/drm/imagination/pvr_drv.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -515,7 +514,8 @@ pvr_dev_query_quirks_get(struct pvr_device *pvr_dev, if (err < 0) return err; - args->size = sizeof(query); + if (args->size > sizeof(query)) + args->size = sizeof(query); return 0; } @@ -596,7 +596,8 @@ pvr_dev_query_enhancements_get(struct pvr_device *pvr_dev, if (err < 0) return err; - args->size = sizeof(query); + if (args->size > sizeof(query)) + args->size = sizeof(query); return 0; } @@ -1255,14 +1256,13 @@ pvr_set_uobj_array(const struct drm_pvr_obj_array *out, u32 min_stride, u32 obj_ if (copy_to_user(out_ptr, in_ptr, cpy_elem_size)) return -EFAULT; - out_ptr += obj_size; - in_ptr += out->stride; - } + if (out->stride > obj_size && + clear_user(out_ptr + cpy_elem_size, out->stride - obj_size)) { + return -EFAULT; + } - if (out->stride > obj_size && - clear_user(u64_to_user_ptr(out->array + obj_size), - out->stride - obj_size)) { - return -EFAULT; + out_ptr += out->stride; + in_ptr += obj_size; } } diff --git a/drivers/gpu/drm/imagination/pvr_queue.c b/drivers/gpu/drm/imagination/pvr_queue.c index 7ed60e1c1a86..941c017399fc 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.c +++ b/drivers/gpu/drm/imagination/pvr_queue.c @@ -1439,11 +1439,12 @@ void pvr_queue_kill(struct pvr_queue *queue) /** * pvr_queue_destroy() - Destroy a queue. * @queue: The queue to destroy. + * @cleanup_queue_entity: Whether to cleanup the queue entity. * * Cleanup the queue and free the resources attached to it. Should be * called from the context release function. */ -void pvr_queue_destroy(struct pvr_queue *queue) +void pvr_queue_destroy(struct pvr_queue *queue, bool cleanup_queue_entity) { if (!queue) return; @@ -1453,7 +1454,8 @@ void pvr_queue_destroy(struct pvr_queue *queue) mutex_unlock(&queue->ctx->pvr_dev->queues.lock); drm_sched_fini(&queue->scheduler); - drm_sched_entity_fini(&queue->entity); + if (cleanup_queue_entity) + drm_sched_entity_fini(&queue->entity); if (WARN_ON(queue->last_queued_job_scheduled_fence)) dma_fence_put(queue->last_queued_job_scheduled_fence); diff --git a/drivers/gpu/drm/imagination/pvr_queue.h b/drivers/gpu/drm/imagination/pvr_queue.h index 4aa72665ce25..149cc6d124bf 100644 --- a/drivers/gpu/drm/imagination/pvr_queue.h +++ b/drivers/gpu/drm/imagination/pvr_queue.h @@ -158,7 +158,7 @@ struct pvr_queue *pvr_queue_create(struct pvr_context *ctx, void pvr_queue_kill(struct pvr_queue *queue); -void pvr_queue_destroy(struct pvr_queue *queue); +void pvr_queue_destroy(struct pvr_queue *queue, bool cleanup_queue_entity); void pvr_queue_process(struct pvr_queue *queue); diff --git a/drivers/gpu/drm/imagination/pvr_vm.c b/drivers/gpu/drm/imagination/pvr_vm.c index e1ec60f34b6e..396d349fb6ce 100644 --- a/drivers/gpu/drm/imagination/pvr_vm.c +++ b/drivers/gpu/drm/imagination/pvr_vm.c @@ -1019,7 +1019,8 @@ pvr_static_data_areas_get(const struct pvr_device *pvr_dev, if (err < 0) return err; - args->size = sizeof(query); + if (args->size > sizeof(query)) + args->size = sizeof(query); return 0; } @@ -1069,7 +1070,8 @@ pvr_heap_info_get(const struct pvr_device *pvr_dev, if (err < 0) return err; - args->size = sizeof(query); + if (args->size > sizeof(query)) + args->size = sizeof(query); return 0; } diff --git a/drivers/gpu/drm/imx/dc/dc-cf.c b/drivers/gpu/drm/imx/dc/dc-cf.c index 2f077161e912..7c2f7abc5099 100644 --- a/drivers/gpu/drm/imx/dc/dc-cf.c +++ b/drivers/gpu/drm/imx/dc/dc-cf.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-de.c b/drivers/gpu/drm/imx/dc/dc-de.c index 5a3125596fdf..15056590b04d 100644 --- a/drivers/gpu/drm/imx/dc/dc-de.c +++ b/drivers/gpu/drm/imx/dc/dc-de.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-drv.c b/drivers/gpu/drm/imx/dc/dc-drv.c index 04f021d2d6cf..13795a2ad735 100644 --- a/drivers/gpu/drm/imx/dc/dc-drv.c +++ b/drivers/gpu/drm/imx/dc/dc-drv.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-ed.c b/drivers/gpu/drm/imx/dc/dc-ed.c index d42f33d6f3fc..de1b71315eab 100644 --- a/drivers/gpu/drm/imx/dc/dc-ed.c +++ b/drivers/gpu/drm/imx/dc/dc-ed.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-fg.c b/drivers/gpu/drm/imx/dc/dc-fg.c index 28f372be9247..3741dc66c0d9 100644 --- a/drivers/gpu/drm/imx/dc/dc-fg.c +++ b/drivers/gpu/drm/imx/dc/dc-fg.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-fl.c b/drivers/gpu/drm/imx/dc/dc-fl.c index 3ce24c72aa13..9f03df44a63a 100644 --- a/drivers/gpu/drm/imx/dc/dc-fl.c +++ b/drivers/gpu/drm/imx/dc/dc-fl.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-fw.c b/drivers/gpu/drm/imx/dc/dc-fw.c index acb2d4d9e2ec..14512c01ea78 100644 --- a/drivers/gpu/drm/imx/dc/dc-fw.c +++ b/drivers/gpu/drm/imx/dc/dc-fw.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-lb.c b/drivers/gpu/drm/imx/dc/dc-lb.c index ca1d714c8d6e..cb614f3c2f69 100644 --- a/drivers/gpu/drm/imx/dc/dc-lb.c +++ b/drivers/gpu/drm/imx/dc/dc-lb.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-pe.c b/drivers/gpu/drm/imx/dc/dc-pe.c index 6676c22f3f45..4eb8c11de99c 100644 --- a/drivers/gpu/drm/imx/dc/dc-pe.c +++ b/drivers/gpu/drm/imx/dc/dc-pe.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/dc/dc-tc.c b/drivers/gpu/drm/imx/dc/dc-tc.c index 0bfd381b2cea..d0d4faba790e 100644 --- a/drivers/gpu/drm/imx/dc/dc-tc.c +++ b/drivers/gpu/drm/imx/dc/dc-tc.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c index f52832b43aca..c67fe80b8115 100644 --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/mediatek/mtk_cec.c b/drivers/gpu/drm/mediatek/mtk_cec.c index b8ccd6e55bed..4a40e510e7db 100644 --- a/drivers/gpu/drm/mediatek/mtk_cec.c +++ b/drivers/gpu/drm/mediatek/mtk_cec.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "mtk_cec.h" diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c index 7982788ae9df..f903656ea0ef 100644 --- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c +++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c index 4412bd678108..867918e9f498 100644 --- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/mxsfb/mxsfb_drv.c b/drivers/gpu/drm/mxsfb/mxsfb_drv.c index 0b756da2fec2..9b8fbda85d28 100644 --- a/drivers/gpu/drm/mxsfb/mxsfb_drv.c +++ b/drivers/gpu/drm/mxsfb/mxsfb_drv.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-arm-versatile.c b/drivers/gpu/drm/panel/panel-arm-versatile.c index ea5119018df4..cffee9838324 100644 --- a/drivers/gpu/drm/panel/panel-arm-versatile.c +++ b/drivers/gpu/drm/panel/panel-arm-versatile.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-auo-a030jtn01.c b/drivers/gpu/drm/panel/panel-auo-a030jtn01.c index 6e52bf6830e1..d71850b24ffa 100644 --- a/drivers/gpu/drm/panel/panel-auo-a030jtn01.c +++ b/drivers/gpu/drm/panel/panel-auo-a030jtn01.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-boe-td4320.c b/drivers/gpu/drm/panel/panel-boe-td4320.c index 1956daa2c71b..23558a76dd72 100644 --- a/drivers/gpu/drm/panel/panel-boe-td4320.c +++ b/drivers/gpu/drm/panel/panel-boe-td4320.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c index 6225501cb174..8c3a231c147d 100644 --- a/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c +++ b/drivers/gpu/drm/panel/panel-feixin-k101-im2ba02.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c index dbdb7e3cb7b6..c1d8ca5ca6e1 100644 --- a/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c +++ b/drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #define FEIYANG_INIT_CMD_LEN 2 diff --git a/drivers/gpu/drm/panel/panel-himax-hx83112b.c b/drivers/gpu/drm/panel/panel-himax-hx83112b.c index 263f79a967de..41f21f8c1373 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx83112b.c +++ b/drivers/gpu/drm/panel/panel-himax-hx83112b.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-himax-hx83121a.c b/drivers/gpu/drm/panel/panel-himax-hx83121a.c index e31e2fba0a78..3b6a562c4d11 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx83121a.c +++ b/drivers/gpu/drm/panel/panel-himax-hx83121a.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-himax-hx8394.c b/drivers/gpu/drm/panel/panel-himax-hx8394.c index bf80354567df..416203da2f45 100644 --- a/drivers/gpu/drm/panel/panel-himax-hx8394.c +++ b/drivers/gpu/drm/panel/panel-himax-hx8394.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-hydis-hv101hd1.c b/drivers/gpu/drm/panel/panel-hydis-hv101hd1.c index 46426c388932..0a96eb0fae1e 100644 --- a/drivers/gpu/drm/panel/panel-hydis-hv101hd1.c +++ b/drivers/gpu/drm/panel/panel-hydis-hv101hd1.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c index f7425dfaa50d..8115a3158492 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9341.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9341.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c index ecdbed8d4a3a..ad33414719fc 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e-dsi.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-lg-ld070wx3.c b/drivers/gpu/drm/panel/panel-lg-ld070wx3.c index 00cbfc5518a5..0280addb6500 100644 --- a/drivers/gpu/drm/panel/panel-lg-ld070wx3.c +++ b/drivers/gpu/drm/panel/panel-lg-ld070wx3.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-motorola-mot.c b/drivers/gpu/drm/panel/panel-motorola-mot.c index eb1f86c3d704..d5b1a6b72ebc 100644 --- a/drivers/gpu/drm/panel/panel-motorola-mot.c +++ b/drivers/gpu/drm/panel/panel-motorola-mot.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-novatek-nt35532.c b/drivers/gpu/drm/panel/panel-novatek-nt35532.c index 184f61bca7ca..edea766a3c44 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt35532.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt35532.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-novatek-nt37801.c b/drivers/gpu/drm/panel/panel-novatek-nt37801.c index d6a37d7e0cc6..861e999250f9 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt37801.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt37801.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c index 60701521c3b1..130520558a81 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-raydium-rm67200.c b/drivers/gpu/drm/panel/panel-raydium-rm67200.c index 333faed62da7..b2ba006c06f6 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm67200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm67200.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c index 669b5f5c1ad9..c535dc931903 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c @@ -8,7 +8,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-renesas-r61307.c b/drivers/gpu/drm/panel/panel-renesas-r61307.c index d8185cc1b5d6..53556452e746 100644 --- a/drivers/gpu/drm/panel/panel-renesas-r61307.c +++ b/drivers/gpu/drm/panel/panel-renesas-r61307.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-renesas-r69328.c b/drivers/gpu/drm/panel/panel-renesas-r69328.c index bfe2787f8f53..81b77141b4e4 100644 --- a/drivers/gpu/drm/panel/panel-renesas-r69328.c +++ b/drivers/gpu/drm/panel/panel-renesas-r69328.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c b/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c index 1618841b7caa..2f8fa95dd7fb 100644 --- a/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c +++ b/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c index ba1a02000bb9..1b14aa4efe35 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6d16d0.c @@ -11,7 +11,6 @@ #include #include #include -#include #include struct s6d16d0 { diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c index 6f3d39556f92..e05199ce14ee 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63j0x03.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c index a89d925fdfb2..2630975c111b 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e63m0-dsi.c @@ -6,7 +6,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c index 7e2f4e043d62..77fee36dbb55 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e88a0-ams427ap24.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-samsung-s6e8fc0-m1906f9.c b/drivers/gpu/drm/panel/panel-samsung-s6e8fc0-m1906f9.c index 199ff99efd78..2fae0dc6c424 100644 --- a/drivers/gpu/drm/panel/panel-samsung-s6e8fc0-m1906f9.c +++ b/drivers/gpu/drm/panel/panel-samsung-s6e8fc0-m1906f9.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-sitronix-st7703.c b/drivers/gpu/drm/panel/panel-sitronix-st7703.c index 6c348fe28955..f1641c9c7d13 100644 --- a/drivers/gpu/drm/panel/panel-sitronix-st7703.c +++ b/drivers/gpu/drm/panel/panel-sitronix-st7703.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-summit.c b/drivers/gpu/drm/panel/panel-summit.c index 6d40b9ddfe02..84435be52424 100644 --- a/drivers/gpu/drm/panel/panel-summit.c +++ b/drivers/gpu/drm/panel/panel-summit.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include -#include #include #include #include diff --git a/drivers/gpu/drm/panel/panel-visionox-rm69299.c b/drivers/gpu/drm/panel/panel-visionox-rm69299.c index f1430370ff94..50f8a84537ca 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm69299.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm69299.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panel/panel-visionox-rm692e5.c b/drivers/gpu/drm/panel/panel-visionox-rm692e5.c index e53645d59413..9567a6125565 100644 --- a/drivers/gpu/drm/panel/panel-visionox-rm692e5.c +++ b/drivers/gpu/drm/panel/panel-visionox-rm692e5.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/panthor/panthor_device.c b/drivers/gpu/drm/panthor/panthor_device.c index bd417d6ae8c0..0b25abebb803 100644 --- a/drivers/gpu/drm/panthor/panthor_device.c +++ b/drivers/gpu/drm/panthor/panthor_device.c @@ -207,6 +207,7 @@ int panthor_device_init(struct panthor_device *ptdev) *dummy_page_virt = 1; INIT_WORK(&ptdev->reset.work, panthor_device_reset_work); + disable_work(&ptdev->reset.work); ptdev->reset.wq = alloc_ordered_workqueue("panthor-reset-wq", 0); if (!ptdev->reset.wq) return -ENOMEM; @@ -285,6 +286,9 @@ int panthor_device_init(struct panthor_device *ptdev) panthor_gem_init(ptdev); + /* Now that everything is initialized, we can enable the reset work. */ + enable_work(&ptdev->reset.work); + /* ~3 frames */ pm_runtime_set_autosuspend_delay(ptdev->base.dev, 50); pm_runtime_use_autosuspend(ptdev->base.dev); diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index 35679bfa1f3a..0fda64fbe5f2 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -512,9 +512,6 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) struct panthor_irq *pirq = data; \ enum panthor_irq_state old_state; \ \ - if (!gpu_read(pirq->iomem, INT_STAT)) \ - return IRQ_NONE; \ - \ guard(spinlock_irqsave)(&pirq->mask_lock); \ old_state = atomic_cmpxchg(&pirq->state, \ PANTHOR_IRQ_STATE_ACTIVE, \ @@ -522,6 +519,13 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) if (old_state != PANTHOR_IRQ_STATE_ACTIVE) \ return IRQ_NONE; \ \ + if (!gpu_read(pirq->iomem, INT_STAT)) { \ + atomic_cmpxchg(&pirq->state, \ + PANTHOR_IRQ_STATE_PROCESSING, \ + PANTHOR_IRQ_STATE_ACTIVE); \ + return IRQ_NONE; \ + } \ + \ gpu_write(pirq->iomem, INT_MASK, 0); \ return IRQ_WAKE_THREAD; \ } \ @@ -584,14 +588,15 @@ static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq) \ static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \ struct panthor_irq *pirq, \ - int irq, u32 mask, void __iomem *iomem) \ + int irq, void __iomem *iomem) \ { \ pirq->ptdev = ptdev; \ pirq->irq = irq; \ - pirq->mask = mask; \ + pirq->mask = 0; \ pirq->iomem = iomem; \ spin_lock_init(&pirq->mask_lock); \ - panthor_ ## __name ## _irq_resume(pirq); \ + atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDED); \ + gpu_write(pirq->iomem, INT_MASK, 0); \ \ return devm_request_threaded_irq(ptdev->base.dev, irq, \ panthor_ ## __name ## _irq_raw_handler, \ diff --git a/drivers/gpu/drm/panthor/panthor_fw.c b/drivers/gpu/drm/panthor/panthor_fw.c index 986151681b24..de8e6689a869 100644 --- a/drivers/gpu/drm/panthor/panthor_fw.c +++ b/drivers/gpu/drm/panthor/panthor_fw.c @@ -1279,9 +1279,7 @@ void panthor_fw_unplug(struct panthor_device *ptdev) if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev)) { /* Make sure the IRQ handler cannot be called after that point. */ - if (ptdev->fw->irq.irq) - panthor_job_irq_suspend(&ptdev->fw->irq); - + panthor_job_irq_suspend(&ptdev->fw->irq); panthor_fw_stop(ptdev); } @@ -1476,7 +1474,7 @@ int panthor_fw_init(struct panthor_device *ptdev) if (irq <= 0) return -ENODEV; - ret = panthor_request_job_irq(ptdev, &fw->irq, irq, 0, + ret = panthor_request_job_irq(ptdev, &fw->irq, irq, ptdev->iomem + JOB_INT_BASE); if (ret) { drm_err(&ptdev->base, "failed to request job irq"); diff --git a/drivers/gpu/drm/panthor/panthor_gpu.c b/drivers/gpu/drm/panthor/panthor_gpu.c index e52c5675981f..c013d6bf9a59 100644 --- a/drivers/gpu/drm/panthor/panthor_gpu.c +++ b/drivers/gpu/drm/panthor/panthor_gpu.c @@ -170,11 +170,12 @@ int panthor_gpu_init(struct panthor_device *ptdev) return irq; ret = panthor_request_gpu_irq(ptdev, &ptdev->gpu->irq, irq, - GPU_INTERRUPTS_MASK, ptdev->iomem + GPU_INT_BASE); if (ret) return ret; + panthor_gpu_irq_enable_events(&ptdev->gpu->irq, GPU_INTERRUPTS_MASK); + panthor_gpu_irq_resume(&ptdev->gpu->irq); return 0; } diff --git a/drivers/gpu/drm/panthor/panthor_mmu.c b/drivers/gpu/drm/panthor/panthor_mmu.c index 1f6b9242279c..f45ef5824ff2 100644 --- a/drivers/gpu/drm/panthor/panthor_mmu.c +++ b/drivers/gpu/drm/panthor/panthor_mmu.c @@ -3405,7 +3405,6 @@ int panthor_mmu_init(struct panthor_device *ptdev) return -ENODEV; ret = panthor_request_mmu_irq(ptdev, &mmu->irq, irq, - panthor_mmu_fault_mask(ptdev, ~0), ptdev->iomem + MMU_INT_BASE); if (ret) return ret; @@ -3423,7 +3422,13 @@ int panthor_mmu_init(struct panthor_device *ptdev) ptdev->gpu_info.mmu_features |= BITS_PER_LONG; } - return drmm_add_action_or_reset(&ptdev->base, panthor_mmu_release_wq, mmu->vm.wq); + ret = drmm_add_action_or_reset(&ptdev->base, panthor_mmu_release_wq, mmu->vm.wq); + if (ret) + return ret; + + panthor_mmu_irq_enable_events(&mmu->irq, panthor_mmu_fault_mask(ptdev, ~0)); + panthor_mmu_irq_resume(&mmu->irq); + return 0; } #ifdef CONFIG_DEBUG_FS diff --git a/drivers/gpu/drm/panthor/panthor_pwr.c b/drivers/gpu/drm/panthor/panthor_pwr.c index 7c7f424a1436..f2c2c3000590 100644 --- a/drivers/gpu/drm/panthor/panthor_pwr.c +++ b/drivers/gpu/drm/panthor/panthor_pwr.c @@ -453,7 +453,8 @@ void panthor_pwr_unplug(struct panthor_device *ptdev) return; /* Make sure the IRQ handler is not running after that point. */ - panthor_pwr_irq_suspend(&ptdev->pwr->irq); + if (!IS_ENABLED(CONFIG_PM) || pm_runtime_active(ptdev->base.dev)) + panthor_pwr_irq_suspend(&ptdev->pwr->irq); /* Wake-up all waiters. */ spin_lock_irqsave(&ptdev->pwr->reqs_lock, flags); @@ -483,12 +484,13 @@ int panthor_pwr_init(struct panthor_device *ptdev) if (irq < 0) return irq; - err = panthor_request_pwr_irq( - ptdev, &pwr->irq, irq, PWR_INTERRUPTS_MASK, - pwr->iomem + PWR_INT_BASE); + err = panthor_request_pwr_irq(ptdev, &pwr->irq, irq, + pwr->iomem + PWR_INT_BASE); if (err) return err; + panthor_pwr_irq_enable_events(&pwr->irq, PWR_INTERRUPTS_MASK); + panthor_pwr_irq_resume(&pwr->irq); return 0; } diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c index 5b34032deff8..298b046c95ed 100644 --- a/drivers/gpu/drm/panthor/panthor_sched.c +++ b/drivers/gpu/drm/panthor/panthor_sched.c @@ -1057,7 +1057,8 @@ group_unbind_locked(struct panthor_group *group) /* Tiler OOM events will be re-issued next time the group is scheduled. */ atomic_set(&group->tiler_oom, 0); - cancel_work(&group->tiler_oom_work); + if (cancel_work(&group->tiler_oom_work)) + group_put(group); for (u32 i = 0; i < group->queue_count; i++) group->queues[i]->doorbell_id = -1; @@ -1151,15 +1152,14 @@ queue_suspend_timeout_locked(struct panthor_queue *queue) static void queue_suspend_timeout(struct panthor_queue *queue) { - spin_lock(&queue->fence_ctx.lock); + guard(spinlock_irqsave)(&queue->fence_ctx.lock); queue_suspend_timeout_locked(queue); - spin_unlock(&queue->fence_ctx.lock); } static void queue_resume_timeout(struct panthor_queue *queue) { - spin_lock(&queue->fence_ctx.lock); + guard(spinlock_irqsave)(&queue->fence_ctx.lock); if (queue_timeout_is_suspended(queue)) { mod_delayed_work(queue->scheduler.timeout_wq, @@ -1168,8 +1168,6 @@ queue_resume_timeout(struct panthor_queue *queue) queue->timeout.remaining = MAX_SCHEDULE_TIMEOUT; } - - spin_unlock(&queue->fence_ctx.lock); } /** @@ -1542,7 +1540,7 @@ cs_slot_process_fault_event_locked(struct panthor_device *ptdev, u64 cs_extract = queue->iface.output->extract; struct panthor_job *job; - spin_lock(&queue->fence_ctx.lock); + guard(spinlock_irqsave)(&queue->fence_ctx.lock); list_for_each_entry(job, &queue->fence_ctx.in_flight_jobs, node) { if (cs_extract >= job->ringbuf.end) continue; @@ -1552,7 +1550,6 @@ cs_slot_process_fault_event_locked(struct panthor_device *ptdev, dma_fence_set_error(job->done_fence, -EINVAL); } - spin_unlock(&queue->fence_ctx.lock); } if (group) { @@ -1604,7 +1601,10 @@ static int group_process_tiler_oom(struct panthor_group *group, u32 cs_id) if (unlikely(csg_id < 0)) return 0; - if (IS_ERR(heaps) || frag_end > vt_end || vt_end >= vt_start) { + if (IS_ERR(heaps)) { + ret = -EINVAL; + heaps = NULL; + } else if (frag_end > vt_end || vt_end >= vt_start) { ret = -EINVAL; } else { /* We do the allocation without holding the scheduler lock to avoid @@ -2183,13 +2183,13 @@ group_term_post_processing(struct panthor_group *group) if (!queue) continue; - spin_lock(&queue->fence_ctx.lock); - list_for_each_entry_safe(job, tmp, &queue->fence_ctx.in_flight_jobs, node) { - list_move_tail(&job->node, &faulty_jobs); - dma_fence_set_error(job->done_fence, err); - dma_fence_signal_locked(job->done_fence); + scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock) { + list_for_each_entry_safe(job, tmp, &queue->fence_ctx.in_flight_jobs, node) { + list_move_tail(&job->node, &faulty_jobs); + dma_fence_set_error(job->done_fence, err); + dma_fence_signal_locked(job->done_fence); + } } - spin_unlock(&queue->fence_ctx.lock); /* Manually update the syncobj seqno to unblock waiters. */ syncobj = group->syncobjs->kmap + (i * sizeof(*syncobj)); @@ -2368,7 +2368,13 @@ tick_ctx_apply(struct panthor_scheduler *sched, struct panthor_sched_tick_ctx *c csg_iface = panthor_fw_get_csg_iface(ptdev, csg_id); csg_slot = &sched->csg_slots[csg_id]; - group_bind_locked(group, csg_id); + ret = group_bind_locked(group, csg_id); + if (ret) { + panthor_device_schedule_reset(ptdev); + ctx->csg_upd_failed_mask |= BIT(csg_id); + return; + } + csg_slot_prog_locked(ptdev, csg_id, new_csg_prio--); csgs_upd_ctx_queue_reqs(ptdev, &upd_ctx, csg_id, group->state == PANTHOR_CS_GROUP_SUSPENDED ? @@ -2668,7 +2674,14 @@ static void sched_resume_tick(struct panthor_device *ptdev) else delay_jiffies = 0; - sched_queue_delayed_work(sched, tick, delay_jiffies); + /* We schedule immediate ticks when we need to process events on CSGs, + * but those don't change the resched_target because we want the other + * groups to stay scheduled for the remaining of the GPU timeslot they + * were given. Make sure those immediate ticks don't get overruled by + * a sched_queue_delayed_work() that would delay the tick execution. + */ + if (!delayed_work_pending(&sched->tick_work)) + sched_queue_delayed_work(sched, tick, delay_jiffies); } static void group_schedule_locked(struct panthor_group *group, u32 queue_mask) @@ -3049,39 +3062,39 @@ static bool queue_check_job_completion(struct panthor_queue *queue) LIST_HEAD(done_jobs); cookie = dma_fence_begin_signalling(); - spin_lock(&queue->fence_ctx.lock); - list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) { - if (!syncobj) { - struct panthor_group *group = job->group; + scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock) { + list_for_each_entry_safe(job, job_tmp, &queue->fence_ctx.in_flight_jobs, node) { + if (!syncobj) { + struct panthor_group *group = job->group; - syncobj = group->syncobjs->kmap + - (job->queue_idx * sizeof(*syncobj)); + syncobj = group->syncobjs->kmap + + (job->queue_idx * sizeof(*syncobj)); + } + + if (syncobj->seqno < job->done_fence->seqno) + break; + + list_move_tail(&job->node, &done_jobs); + dma_fence_signal_locked(job->done_fence); } - if (syncobj->seqno < job->done_fence->seqno) - break; + if (list_empty(&queue->fence_ctx.in_flight_jobs)) { + /* If we have no job left, we cancel the timer, and reset remaining + * time to its default so it can be restarted next time + * queue_resume_timeout() is called. + */ + queue_suspend_timeout_locked(queue); - list_move_tail(&job->node, &done_jobs); - dma_fence_signal_locked(job->done_fence); + /* If there's no job pending, we consider it progress to avoid a + * spurious timeout if the timeout handler and the sync update + * handler raced. + */ + progress = true; + } else if (!list_empty(&done_jobs)) { + queue_reset_timeout_locked(queue); + progress = true; + } } - - if (list_empty(&queue->fence_ctx.in_flight_jobs)) { - /* If we have no job left, we cancel the timer, and reset remaining - * time to its default so it can be restarted next time - * queue_resume_timeout() is called. - */ - queue_suspend_timeout_locked(queue); - - /* If there's no job pending, we consider it progress to avoid a - * spurious timeout if the timeout handler and the sync update - * handler raced. - */ - progress = true; - } else if (!list_empty(&done_jobs)) { - queue_reset_timeout_locked(queue); - progress = true; - } - spin_unlock(&queue->fence_ctx.lock); dma_fence_end_signalling(cookie); list_for_each_entry_safe(job, job_tmp, &done_jobs, node) { @@ -3346,9 +3359,8 @@ queue_run_job(struct drm_sched_job *sched_job) job->ringbuf.end = job->ringbuf.start + (instrs.count * sizeof(u64)); panthor_job_get(&job->base); - spin_lock(&queue->fence_ctx.lock); - list_add_tail(&job->node, &queue->fence_ctx.in_flight_jobs); - spin_unlock(&queue->fence_ctx.lock); + scoped_guard(spinlock_irqsave, &queue->fence_ctx.lock) + list_add_tail(&job->node, &queue->fence_ctx.in_flight_jobs); /* Make sure the ring buffer is updated before the INSERT * register. diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 83f1ae31cbdb..9755e717ca8b 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -932,7 +932,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev) ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk, dep_table); if (ret) { - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); + r600_free_extended_power_table(rdev); return ret; } } @@ -943,8 +943,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev) ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk, dep_table); if (ret) { - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); - kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries); + r600_free_extended_power_table(rdev); return ret; } } @@ -955,9 +954,7 @@ int r600_parse_extended_power_table(struct radeon_device *rdev) ret = r600_parse_clk_voltage_dep_table(&rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk, dep_table); if (ret) { - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries); - kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries); - kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries); + r600_free_extended_power_table(rdev); return ret; } } @@ -1296,17 +1293,29 @@ void r600_free_extended_power_table(struct radeon_device *rdev) struct radeon_dpm_dynamic_state *dyn_state = &rdev->pm.dpm.dyn_state; kfree(dyn_state->vddc_dependency_on_sclk.entries); + dyn_state->vddc_dependency_on_sclk.entries = NULL; kfree(dyn_state->vddci_dependency_on_mclk.entries); + dyn_state->vddci_dependency_on_mclk.entries = NULL; kfree(dyn_state->vddc_dependency_on_mclk.entries); + dyn_state->vddc_dependency_on_mclk.entries = NULL; kfree(dyn_state->mvdd_dependency_on_mclk.entries); + dyn_state->mvdd_dependency_on_mclk.entries = NULL; kfree(dyn_state->cac_leakage_table.entries); + dyn_state->cac_leakage_table.entries = NULL; kfree(dyn_state->phase_shedding_limits_table.entries); + dyn_state->phase_shedding_limits_table.entries = NULL; kfree(dyn_state->ppm_table); + dyn_state->ppm_table = NULL; kfree(dyn_state->cac_tdp_table); + dyn_state->cac_tdp_table = NULL; kfree(dyn_state->vce_clock_voltage_dependency_table.entries); + dyn_state->vce_clock_voltage_dependency_table.entries = NULL; kfree(dyn_state->uvd_clock_voltage_dependency_table.entries); + dyn_state->uvd_clock_voltage_dependency_table.entries = NULL; kfree(dyn_state->samu_clock_voltage_dependency_table.entries); + dyn_state->samu_clock_voltage_dependency_table.entries = NULL; kfree(dyn_state->acp_clock_voltage_dependency_table.entries); + dyn_state->acp_clock_voltage_dependency_table.entries = NULL; } enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c index c0176e5de9a8..8e7fac7a893b 100644 --- a/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c +++ b/drivers/gpu/drm/renesas/rcar-du/rcar_dw_hdmi.c @@ -7,7 +7,6 @@ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) */ -#include #include #include diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c index 9dc207c2d20d..6db88665060d 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi2-rockchip.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c index 45a6dae4de31..33ff195bd2e6 100644 --- a/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/inno_hdmi-rockchip.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 1d8473a6dfd1..c44648e1bc0d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c index b2f8ebf90968..72301e0a3e0a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/gpu/drm/sprd/sprd_drm.c b/drivers/gpu/drm/sprd/sprd_drm.c index ceacdcb7c566..c2fd5380a834 100644 --- a/drivers/gpu/drm/sprd/sprd_drm.c +++ b/drivers/gpu/drm/sprd/sprd_drm.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 360a88ca8f0c..b9f8f68f01f9 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c index 144b7cda989a..0967b9b3451d 100644 --- a/drivers/gpu/drm/stm/drv.c +++ b/drivers/gpu/drm/stm/drv.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c index 58eae6804cc8..a3eae5b2c26e 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/sun4i/sun6i_drc.c b/drivers/gpu/drm/sun4i/sun6i_drc.c index 310c7e0daede..0050c1b46ea8 100644 --- a/drivers/gpu/drm/sun4i/sun6i_drc.c +++ b/drivers/gpu/drm/sun4i/sun6i_drc.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index e7f675c15c20..1d6c9a423a41 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -6,7 +6,6 @@ /* LCDC DRM driver, based on da8xx-fb */ -#include #include #include #include diff --git a/drivers/gpu/drm/tiny/sharp-memory.c b/drivers/gpu/drm/tiny/sharp-memory.c index 506e6432e70d..7efd7b567f3b 100644 --- a/drivers/gpu/drm/tiny/sharp-memory.c +++ b/drivers/gpu/drm/tiny/sharp-memory.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index 2afc88394d64..53f36626a50d 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include "vc4_drv.h" #include "vc4_regs.h" diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index 66b6f2acf862..bc3f366fc3e6 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 68d097ad9d1d..905b1f42cd98 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -937,7 +937,8 @@ static int virtio_get_edid_block(void *data, u8 *buf, struct virtio_gpu_resp_edid *resp = data; size_t start = block * EDID_LENGTH; - if (start + len > le32_to_cpu(resp->size)) + if (start + len > le32_to_cpu(resp->size) || + start + len > sizeof(resp->edid)) return -EINVAL; memcpy(buf, resp->edid + start, len); return 0; diff --git a/drivers/gpu/drm/xe/Kconfig.profile b/drivers/gpu/drm/xe/Kconfig.profile index 7530df998148..e07517d120e0 100644 --- a/drivers/gpu/drm/xe/Kconfig.profile +++ b/drivers/gpu/drm/xe/Kconfig.profile @@ -1,50 +1,71 @@ # SPDX-License-Identifier: GPL-2.0-only config DRM_XE_JOB_TIMEOUT_MAX - int "Default max job timeout (ms)" + int "Hard upper limit for job timeout (ms)" default 10000 # milliseconds help - Configures the default max job timeout after which job will - be forcefully taken away from scheduler. + Absolute upper bound (in milliseconds) for the per-engine-class job + timeout. This is the maximum value that can be written to the sysfs + job_timeout_ms knob, regardless of privileges. To raise this ceiling, + increase this value and rebuild the kernel. config DRM_XE_JOB_TIMEOUT_MIN - int "Default min job timeout (ms)" + int "Hard lower limit for job timeout (ms)" default 1 # milliseconds help - Configures the default min job timeout after which job will - be forcefully taken away from scheduler. + Absolute lower bound (in milliseconds) for the per-engine-class job + timeout. This is the minimum value that can be written to the sysfs + job_timeout_ms knob, regardless of privileges. + + Note: the job timeout default (5000 ms) is hardcoded in the driver + and is not configurable here. Use the sysfs job_timeout_ms knob at + runtime to change the engine-class default. config DRM_XE_TIMESLICE_MAX - int "Default max timeslice duration (us)" + int "Hard upper limit for timeslice duration (us)" default 10000000 # microseconds help - Configures the default max timeslice duration between multiple - contexts by guc scheduling. + Absolute upper bound (in microseconds) for the timeslice duration. + This caps both the sysfs timeslice_duration_us knob and the value + accepted via the DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE UAPI for + processes with CAP_SYS_NICE when DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT + is enabled. config DRM_XE_TIMESLICE_MIN - int "Default min timeslice duration (us)" + int "Hard lower limit for timeslice duration (us)" default 1 # microseconds help - Configures the default min timeslice duration between multiple - contexts by guc scheduling. + Absolute lower bound (in microseconds) for the timeslice duration. + This caps both the sysfs timeslice_duration_us knob and the value + accepted via the DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE UAPI for + processes with CAP_SYS_NICE when DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT + is enabled. config DRM_XE_PREEMPT_TIMEOUT - int "Preempt timeout (us, jiffy granularity)" + int "Default preempt timeout (us, jiffy granularity)" default 640000 # microseconds help - How long to wait (in microseconds) for a preemption event to occur - when submitting a new context. If the current context does not hit - an arbitration point and yield to HW before the timer expires, the - HW will be reset to allow the more important context to execute. + Initial per-engine-class preemption timeout (in microseconds). This + is the value the driver programs at boot; it can be changed at + runtime via the sysfs preempt_timeout_us knob. + + This is how long the driver waits for the current context to reach + an arbitration point and yield the GPU voluntarily when a + higher-priority context becomes runnable. If the context does not + yield before the timer expires, the HW is reset to allow the + higher-priority context to execute. + + The range userspace may write via sysfs is bounded by + DRM_XE_PREEMPT_TIMEOUT_MIN and DRM_XE_PREEMPT_TIMEOUT_MAX. config DRM_XE_PREEMPT_TIMEOUT_MAX - int "Default max preempt timeout (us)" + int "Hard upper limit for preempt timeout (us)" default 10000000 # microseconds help - Configures the default max preempt timeout after which context - will be forcefully taken away and higher priority context will - run. + Absolute upper bound (in microseconds) for the per-engine-class + preemption timeout. This is the maximum value that can be written to + the sysfs preempt_timeout_us knob, regardless of privileges. config DRM_XE_PREEMPT_TIMEOUT_MIN - int "Default min preempt timeout (us)" + int "Hard lower limit for preempt timeout (us)" default 1 # microseconds help - Configures the default min preempt timeout after which context - will be forcefully taken away and higher priority context will - run. + Absolute lower bound (in microseconds) for the per-engine-class + preemption timeout. This is the minimum value that can be written to + the sysfs preempt_timeout_us knob, regardless of privileges. config DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT bool "Default configuration of limitation on scheduler timeout" default y diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 8e7b146880f4..6d728f8c4c39 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -101,6 +101,7 @@ xe-y += xe_bb.o \ xe_page_reclaim.o \ xe_pat.o \ xe_pci.o \ + xe_pci_error.o \ xe_pci_rebar.o \ xe_pcode.o \ xe_pm.o \ @@ -278,6 +279,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_dp_aux.o \ i915-display/intel_dp_aux_backlight.o \ i915-display/intel_dp_hdcp.o \ + i915-display/intel_dp_link_caps.o \ i915-display/intel_dp_link_training.o \ i915-display/intel_dp_mst.o \ i915-display/intel_dp_test.o \ diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index 810d93fefcbc..92a4573db28a 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -19,7 +19,6 @@ #include "intel_acpi.h" #include "intel_audio.h" -#include "intel_bw.h" #include "intel_display.h" #include "intel_display_core.h" #include "intel_display_device.h" @@ -29,8 +28,6 @@ #include "intel_dmc.h" #include "intel_dmc_wl.h" #include "intel_dp.h" -#include "intel_dram.h" -#include "intel_encoder.h" #include "intel_fbdev.h" #include "intel_hdcp.h" #include "intel_hotplug.h" @@ -84,10 +81,8 @@ static void xe_display_fini_early(void *arg) if (!xe->info.probe_display) return; - intel_hpd_cancel_work(display); - intel_display_driver_remove_nogem(display); intel_display_driver_remove_noirq(display); - intel_opregion_cleanup(display); + intel_display_driver_remove_nogem(display); intel_display_power_cleanup(display); } @@ -113,22 +108,9 @@ int xe_display_init_early(struct xe_device *xe) return 0; } - /* Early display init.. */ - intel_opregion_setup(display); - - /* - * Fill the dram structure to get the system dram info. This will be - * used for memory latency calculation. - */ - err = intel_dram_detect(display); - if (err) - goto err_opregion; - - intel_bw_init_hw(display); - err = intel_display_driver_probe_noirq(display); if (err) - goto err_opregion; + return err; err = intel_display_driver_probe_nogem(display); if (err) @@ -138,8 +120,7 @@ int xe_display_init_early(struct xe_device *xe) err_noirq: intel_display_driver_remove_noirq(display); intel_display_power_cleanup(display); -err_opregion: - intel_opregion_cleanup(display); + return err; } @@ -191,6 +172,30 @@ void xe_display_unregister(struct xe_device *xe) intel_display_driver_unregister(display); } +void xe_display_shutdown(struct xe_device *xe) +{ + struct intel_display *display = xe->display; + + if (!xe->info.probe_display) + return; + + intel_display_driver_shutdown(display); + + intel_opregion_suspend(display, PCI_D3cold); + + intel_dmc_suspend(display); +} + +void xe_display_shutdown_late(struct xe_device *xe) +{ + struct intel_display *display = xe->display; + + if (!xe->info.probe_display) + return; + + intel_display_driver_shutdown_late(display); +} + /* IRQ-related functions */ void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl) @@ -244,6 +249,59 @@ static bool suspend_to_idle(void) return false; } +void xe_display_pm_suspend(struct xe_device *xe) +{ + struct intel_display *display = xe->display; + bool s2idle = suspend_to_idle(); + + if (!xe->info.probe_display) + return; + + intel_display_driver_pm_suspend(display); + + intel_opregion_suspend(display, s2idle ? PCI_D1 : PCI_D3cold); + + intel_dmc_suspend(display); +} + +void xe_display_pm_suspend_late(struct xe_device *xe) +{ + struct intel_display *display = xe->display; + bool s2idle = suspend_to_idle(); + + if (!xe->info.probe_display) + return; + + intel_display_driver_pm_suspend_late(display, s2idle); +} + +void xe_display_pm_resume_early(struct xe_device *xe) +{ + struct intel_display *display = xe->display; + + if (!xe->info.probe_display) + return; + + intel_display_driver_pm_resume_early(display); +} + +void xe_display_pm_resume(struct xe_device *xe) +{ + struct intel_display *display = xe->display; + + if (!xe->info.probe_display) + return; + + intel_dmc_resume(display); + + if (intel_display_device_present(display)) + drm_mode_config_reset(&xe->drm); + + intel_display_driver_init_hw(display); + + intel_display_driver_pm_resume(display); +} + static void xe_display_enable_d3cold(struct xe_device *xe) { struct intel_display *display = xe->display; @@ -291,75 +349,6 @@ static void xe_display_disable_d3cold(struct xe_device *xe) intel_display_power_enable(display); } -void xe_display_pm_suspend(struct xe_device *xe) -{ - struct intel_display *display = xe->display; - bool s2idle = suspend_to_idle(); - - if (!xe->info.probe_display) - return; - - /* - * We do a lot of poking in a lot of registers, make sure they work - * properly. - */ - intel_display_power_disable(display); - drm_client_dev_suspend(&xe->drm); - - if (intel_display_device_present(display)) { - drm_kms_helper_poll_disable(&xe->drm); - intel_display_driver_disable_user_access(display); - intel_display_driver_suspend(display); - } - - intel_display_flush_cleanup_work(display); - - intel_encoder_block_all_hpds(display); - - intel_hpd_cancel_work(display); - - if (intel_display_device_present(display)) { - intel_display_driver_suspend_access(display); - intel_encoder_suspend_all(display); - } - - intel_opregion_suspend(display, s2idle ? PCI_D1 : PCI_D3cold); - - intel_dmc_suspend(display); -} - -void xe_display_pm_shutdown(struct xe_device *xe) -{ - struct intel_display *display = xe->display; - - if (!xe->info.probe_display) - return; - - intel_display_power_disable(display); - drm_client_dev_suspend(&xe->drm); - - if (intel_display_device_present(display)) { - drm_kms_helper_poll_disable(&xe->drm); - intel_display_driver_disable_user_access(display); - intel_display_driver_suspend(display); - } - - intel_display_flush_cleanup_work(display); - intel_dp_mst_suspend(display); - intel_encoder_block_all_hpds(display); - intel_hpd_cancel_work(display); - - if (intel_display_device_present(display)) - intel_display_driver_suspend_access(display); - - intel_encoder_suspend_all(display); - intel_encoder_shutdown_all(display); - - intel_opregion_suspend(display, PCI_D3cold); - - intel_dmc_suspend(display); -} - void xe_display_pm_runtime_suspend(struct xe_device *xe) { struct intel_display *display = xe->display; @@ -375,17 +364,6 @@ void xe_display_pm_runtime_suspend(struct xe_device *xe) intel_hpd_poll_enable(display); } -void xe_display_pm_suspend_late(struct xe_device *xe) -{ - struct intel_display *display = xe->display; - bool s2idle = suspend_to_idle(); - - if (!xe->info.probe_display) - return; - - intel_display_power_suspend_late(display, s2idle); -} - void xe_display_pm_runtime_suspend_late(struct xe_device *xe) { struct intel_display *display = xe->display; @@ -404,68 +382,6 @@ void xe_display_pm_runtime_suspend_late(struct xe_device *xe) intel_dmc_wl_flush_release_work(display); } -void xe_display_pm_shutdown_late(struct xe_device *xe) -{ - struct intel_display *display = xe->display; - - if (!xe->info.probe_display) - return; - - /* - * The only requirement is to reboot with display DC states disabled, - * for now leaving all display power wells in the INIT power domain - * enabled. - */ - intel_display_power_driver_remove(display); -} - -void xe_display_pm_resume_early(struct xe_device *xe) -{ - struct intel_display *display = xe->display; - - if (!xe->info.probe_display) - return; - - intel_display_power_resume_early(display); -} - -void xe_display_pm_resume(struct xe_device *xe) -{ - struct intel_display *display = xe->display; - - if (!xe->info.probe_display) - return; - - intel_dmc_resume(display); - - if (intel_display_device_present(display)) - drm_mode_config_reset(&xe->drm); - - intel_display_driver_init_hw(display); - - if (intel_display_device_present(display)) - intel_display_driver_resume_access(display); - - intel_hpd_init(display); - - intel_encoder_unblock_all_hpds(display); - - if (intel_display_device_present(display)) { - intel_display_driver_resume(display); - drm_kms_helper_poll_enable(&xe->drm); - intel_display_driver_enable_user_access(display); - } - - if (intel_display_device_present(display)) - intel_hpd_poll_disable(display); - - intel_opregion_resume(display); - - drm_client_dev_resume(&xe->drm); - - intel_display_power_enable(display); -} - void xe_display_pm_runtime_resume(struct xe_device *xe) { struct intel_display *display = xe->display; diff --git a/drivers/gpu/drm/xe/display/xe_display.h b/drivers/gpu/drm/xe/display/xe_display.h index 60291cb154df..e5f9aed93206 100644 --- a/drivers/gpu/drm/xe/display/xe_display.h +++ b/drivers/gpu/drm/xe/display/xe_display.h @@ -29,15 +29,16 @@ int xe_display_init(struct xe_device *xe); void xe_display_register(struct xe_device *xe); void xe_display_unregister(struct xe_device *xe); +void xe_display_shutdown(struct xe_device *xe); +void xe_display_shutdown_late(struct xe_device *xe); + void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl); void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir); void xe_display_irq_reset(struct xe_device *xe); void xe_display_irq_postinstall(struct xe_device *xe); void xe_display_pm_suspend(struct xe_device *xe); -void xe_display_pm_shutdown(struct xe_device *xe); void xe_display_pm_suspend_late(struct xe_device *xe); -void xe_display_pm_shutdown_late(struct xe_device *xe); void xe_display_pm_resume_early(struct xe_device *xe); void xe_display_pm_resume(struct xe_device *xe); void xe_display_pm_runtime_suspend(struct xe_device *xe); @@ -65,15 +66,16 @@ static inline int xe_display_init(struct xe_device *xe) { return 0; } static inline void xe_display_register(struct xe_device *xe) {} static inline void xe_display_unregister(struct xe_device *xe) {} +static inline void xe_display_shutdown(struct xe_device *xe) {} +static inline void xe_display_shutdown_late(struct xe_device *xe) {} + static inline void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl) {} static inline void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir) {} static inline void xe_display_irq_reset(struct xe_device *xe) {} static inline void xe_display_irq_postinstall(struct xe_device *xe) {} static inline void xe_display_pm_suspend(struct xe_device *xe) {} -static inline void xe_display_pm_shutdown(struct xe_device *xe) {} static inline void xe_display_pm_suspend_late(struct xe_device *xe) {} -static inline void xe_display_pm_shutdown_late(struct xe_device *xe) {} static inline void xe_display_pm_resume_early(struct xe_device *xe) {} static inline void xe_display_pm_resume(struct xe_device *xe) {} static inline void xe_display_pm_runtime_suspend(struct xe_device *xe) {} diff --git a/drivers/gpu/drm/xe/display/xe_display_bo.c b/drivers/gpu/drm/xe/display/xe_display_bo.c index 7fbac223b097..8953da0136dc 100644 --- a/drivers/gpu/drm/xe/display/xe_display_bo.c +++ b/drivers/gpu/drm/xe/display/xe_display_bo.c @@ -48,7 +48,8 @@ static int xe_display_bo_framebuffer_init(struct drm_gem_object *obj, if (ret) goto err; - if (!(bo->flags & XE_BO_FLAG_FORCE_WC)) { + if (!(bo->flags & XE_BO_FLAG_FORCE_WC) && + bo->ttm.type != ttm_bo_type_sg) { /* * XE_BO_FLAG_FORCE_WC should ideally be set at creation, or is * automatically set when creating FB. We cannot change caching diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c index f93c98bec5b5..5f4a0cd8deca 100644 --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c @@ -331,7 +331,8 @@ static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt, int ret = 0; /* We reject creating !SCANOUT fb's, so this is weird.. */ - drm_WARN_ON(bo->ttm.base.dev, !(bo->flags & XE_BO_FLAG_FORCE_WC)); + drm_WARN_ON(bo->ttm.base.dev, !(bo->flags & XE_BO_FLAG_FORCE_WC) && + bo->ttm.type != ttm_bo_type_sg); if (!vma) return ERR_PTR(-ENODEV); diff --git a/drivers/gpu/drm/xe/display/xe_panic.c b/drivers/gpu/drm/xe/display/xe_panic.c index bebb21d617f0..12c6fb99015d 100644 --- a/drivers/gpu/drm/xe/display/xe_panic.c +++ b/drivers/gpu/drm/xe/display/xe_panic.c @@ -5,8 +5,6 @@ #include #include -#include "intel_display_types.h" -#include "intel_fb.h" #include "xe_bo.h" #include "xe_panic.h" #include "xe_res_cursor.h" @@ -16,6 +14,9 @@ struct intel_panic { struct iosys_map vmap; int page; + + struct xe_bo *bo; + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width); }; static void xe_panic_kunmap(struct intel_panic *panic) @@ -36,14 +37,13 @@ static void xe_panic_kunmap(struct intel_panic *panic) static void xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, unsigned int y, u32 color) { - struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private; - struct intel_panic *panic = fb->panic; - struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base)); + struct intel_panic *panic = sb->private; + struct xe_bo *bo = panic->bo; unsigned int new_page; unsigned int offset; - if (fb->panic_tiling) - offset = fb->panic_tiling(sb->width, x, y); + if (panic->tiling) + offset = panic->tiling(sb->width, x, y); else offset = y * sb->pitch[0] + x * sb->format->cpp[0]; @@ -84,16 +84,22 @@ static struct intel_panic *xe_panic_alloc(void) return panic; } -static int xe_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb) +static int xe_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb, + struct drm_gem_object *obj, + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width)) { - struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private; - struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base)); + struct xe_bo *bo = gem_to_xe_bo(obj); if (xe_bo_is_vram(bo) && !xe_bo_is_visible_vram(bo)) return -ENODEV; panic->page = -1; + panic->bo = bo; + panic->tiling = tiling; + + sb->private = panic; sb->set_pixel = xe_panic_page_set_pixel; + return 0; } diff --git a/drivers/gpu/drm/xe/tests/Makefile b/drivers/gpu/drm/xe/tests/Makefile index 0e3408f4952c..f7aa47f11a36 100644 --- a/drivers/gpu/drm/xe/tests/Makefile +++ b/drivers/gpu/drm/xe/tests/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_test.o xe_test-y = xe_test_mod.o \ xe_args_test.o \ xe_pci_test.o \ + xe_rtp_tables_test.o \ xe_rtp_test.o \ xe_wa_test.o diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/xe_pci.c index 9240aff779da..8df9029afcd3 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -311,40 +311,44 @@ const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char *desc } EXPORT_SYMBOL_IF_KUNIT(xe_pci_id_gen_param); -static void fake_init_devid(struct xe_device *xe) +static int fake_probe_info(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_pci_fake_data *data, + struct xe_probed_info *probed_info) { - /* Nothing to do, just keep zero. */ -} + probed_info->tile_count = 1 + desc->max_remote_tiles; -static int fake_read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, - u32 *ver, u32 *revid) -{ - struct kunit *test = kunit_get_current_test(); - struct xe_pci_fake_data *data = test->priv; - - if (type == GMDID_MEDIA) { - *ver = data->media_verx100; - *revid = xe_step_to_gmdid(data->step.media); + if (!data || desc->pre_gmdid_graphics_ip) { + probed_info->graphics_ip = desc->pre_gmdid_graphics_ip; + probed_info->media_ip = desc->pre_gmdid_media_ip; } else { - *ver = data->graphics_verx100; - *revid = xe_step_to_gmdid(data->step.graphics); + probed_info->graphics_ip = find_graphics_ip(data->graphics_verx100); + + if (data->media_verx100) { + probed_info->media_ip = find_media_ip(data->media_verx100); + xe_assert(xe, probed_info->media_ip); + } } - return 0; -} + xe_assert(xe, probed_info->graphics_ip); + if (!probed_info->graphics_ip) + return -ENODEV; -static void fake_xe_info_probe_tile_count(struct xe_device *xe) -{ - /* Nothing to do, just use the statically defined value. */ + if (data) + probed_info->step = data->step; + + return 0; } int xe_pci_fake_device_init(struct xe_device *xe) { struct kunit *test = kunit_get_current_test(); struct xe_pci_fake_data *data = test->priv; + struct xe_probed_info probed_info = {}; const struct pci_device_id *ent = pciidlist; const struct xe_device_desc *desc; const struct xe_subplatform_desc *subplatform_desc; + int err; if (!data) { desc = (const void *)ent->driver_data; @@ -374,13 +378,12 @@ int xe_pci_fake_device_init(struct xe_device *xe) xe->sriov.__mode = data && data->sriov_mode ? data->sriov_mode : XE_SRIOV_MODE_NONE; - kunit_activate_static_stub(test, init_devid, fake_init_devid); - kunit_activate_static_stub(test, read_gmdid, fake_read_gmdid); - kunit_activate_static_stub(test, xe_info_probe_tile_count, - fake_xe_info_probe_tile_count); + err = fake_probe_info(xe, desc, data, &probed_info); + if (err) + return err; - xe_info_init_early(xe, desc, subplatform_desc); - xe_info_init(xe, desc); + xe_info_init_early(xe, desc, subplatform_desc, &probed_info); + xe_info_init(xe, desc, &probed_info); return 0; } diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c new file mode 100644 index 000000000000..7e2fc39ac62c --- /dev/null +++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright © 2026 Intel Corporation + */ + +#include + +#include "xe_reg_whitelist.h" +#include "xe_rtp_types.h" +#include "xe_tuning.h" +#include "xe_wa.h" + +#define RTP_TABLE_PARAM(table) \ + static const void *table##_gen_params(struct kunit *test, \ + const void *prev, char *desc) \ + { \ + typeof((table.entries)[0]) *__next = prev ? \ + ((typeof(__next))prev) + 1 : (table.entries); \ + if (__next - table.entries < table.n_entries) { \ + scnprintf(desc, KUNIT_PARAM_DESC_SIZE, #table "/%s", __next->name); \ + return __next; \ + } \ + return NULL; \ + } + +static void xe_rtp_table_gt_test(struct kunit *test) +{ + const struct xe_rtp_entry_sr *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + KUNIT_EXPECT_TRUE(test, + entry->rules[i].match_type != XE_RTP_MATCH_ENGINE_CLASS || + entry->flags & XE_RTP_ENTRY_FLAG_FOREACH_ENGINE); + KUNIT_EXPECT_TRUE(test, + entry->rules[i].match_type != XE_RTP_MATCH_NOT_ENGINE_CLASS || + entry->flags & XE_RTP_ENTRY_FLAG_FOREACH_ENGINE); + } +} + +RTP_TABLE_PARAM(gt_was); +RTP_TABLE_PARAM(gt_tunings); + +static void xe_rtp_table_oob_test(struct kunit *test) +{ + const struct xe_rtp_entry *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + u8 match_type = entry->rules[i].match_type; + + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_ENGINE_CLASS); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_NOT_ENGINE_CLASS); + } +} + +RTP_TABLE_PARAM(oob_was); + +static void xe_rtp_table_dev_oob_test(struct kunit *test) +{ + const struct xe_rtp_entry *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + u8 match_type = entry->rules[i].match_type; + + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_ENGINE_CLASS); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_NOT_ENGINE_CLASS); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_VERSION); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_VERSION_RANGE); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_VERSION_ANY_GT); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_GRAPHICS_STEP); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_VERSION); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_VERSION_RANGE); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_VERSION_ANY_GT); + KUNIT_EXPECT_NE(test, match_type, XE_RTP_MATCH_MEDIA_STEP); + } +} + +RTP_TABLE_PARAM(device_oob_was); + +static void xe_rtp_table_missing_upper_bound_test(struct kunit *test) +{ + const struct xe_rtp_entry_sr *entry = test->param_value; + + for (int i = 0; i < entry->n_rules; i++) { + u8 match_type = entry->rules[i].match_type; + + KUNIT_EXPECT_FALSE(test, + match_type == XE_RTP_MATCH_GRAPHICS_VERSION_RANGE && + entry->rules[i].ver_end == XE_RTP_END_VERSION_UNDEFINED); + KUNIT_EXPECT_FALSE(test, + match_type == XE_RTP_MATCH_MEDIA_VERSION_RANGE && + entry->rules[i].ver_end == XE_RTP_END_VERSION_UNDEFINED); + } +} + +RTP_TABLE_PARAM(register_whitelist); + +static struct kunit_case xe_rtp_table_tests[] = { + KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_oob_test, oob_was_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_dev_oob_test, device_oob_was_gen_params), + KUNIT_CASE_PARAM(xe_rtp_table_missing_upper_bound_test, + register_whitelist_gen_params), + {} +}; + +static struct kunit_suite xe_rtp_tables_test_suite = { + .name = "xe_rtp_tables_test", + .test_cases = xe_rtp_table_tests, +}; + +kunit_test_suite(xe_rtp_tables_test_suite); diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_test.c index 642f6e090ad0..367811621880 100644 --- a/drivers/gpu/drm/xe/tests/xe_rtp_test.c +++ b/drivers/gpu/drm/xe/tests/xe_rtp_test.c @@ -54,13 +54,13 @@ struct rtp_to_sr_test_case { unsigned long expected_count_sr_entries; unsigned int expected_sr_errors; unsigned long expected_active; - const struct xe_rtp_entry_sr *entries; + const struct xe_rtp_table_sr table; }; struct rtp_test_case { const char *name; unsigned long expected_active; - const struct xe_rtp_entry *entries; + const struct xe_rtp_table table; }; static bool fake_xe_gt_mcr_check_reg(struct xe_gt *gt, struct xe_reg reg) @@ -280,6 +280,11 @@ static void xe_rtp_rules_tests(struct kunit *test) KUNIT_EXPECT_EQ(test, err, param->expected_err); } +static u32 bits_2_3_set(struct xe_gt *gt, struct xe_hw_engine *hwe) +{ + return REG_BIT(2) | REG_BIT(3); +} + static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { { .name = "coalesce-same-reg", @@ -289,7 +294,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, /* Different bits on the same register: create a single entry */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -298,8 +303,30 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) }, - {} - }, + ), + }, + { + .name = "coalesce-same-reg-literal-and-func", + .expected_reg = REGULAR_REG1, + .expected_set_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2) | REG_BIT(3), + .expected_clr_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2) | REG_BIT(3), + .expected_active = BIT(0) | BIT(1), + .expected_count_sr_entries = 1, + /* Different bits on the same register: create a single entry */ + .table = XE_RTP_TABLE_SR( + { XE_RTP_NAME("basic-1"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, + REG_BIT(0) | REG_BIT(1), + REG_BIT(0) | REG_BIT(1))) + }, + { XE_RTP_NAME("basic-2"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(REGULAR_REG1, + REG_BIT(2) | REG_BIT(3), + bits_2_3_set)) + }, + ), }, { .name = "no-match-no-add", @@ -309,7 +336,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, /* Don't coalesce second entry since rules don't match */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -318,8 +345,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_no)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(1))) }, - {} - }, + ), }, { .name = "two-regs-two-entries", @@ -329,7 +355,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 2, /* Same bits on different registers are not coalesced */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -338,8 +364,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG2, REG_BIT(0))) }, - {} - }, + ), }, { .name = "clr-one-set-other", @@ -349,7 +374,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, /* Check clr vs set actions on different bits */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -358,8 +383,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_BIT(1))) }, - {} - }, + ), }, { #define TEMP_MASK REG_GENMASK(10, 8) @@ -371,14 +395,13 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, /* Check FIELD_SET works */ - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, TEMP_MASK, TEMP_FIELD)) }, - {} - }, + ), #undef TEMP_MASK #undef TEMP_FIELD }, @@ -390,7 +413,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -400,8 +423,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) }, - {} - }, + ), }, { .name = "conflict-not-disjoint", @@ -411,7 +433,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -421,8 +443,31 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(CLR(REGULAR_REG1, REG_GENMASK(1, 0))) }, - {} - }, + ), + }, + { + .name = "conflict-not-disjoint-literal-and-func", + .expected_reg = REGULAR_REG1, + .expected_set_bits = REG_BIT(1) | REG_BIT(2), + .expected_clr_bits = REG_BIT(1) | REG_BIT(2), + .expected_active = BIT(0) | BIT(1), + .expected_count_sr_entries = 1, + .expected_sr_errors = 1, + .table = XE_RTP_TABLE_SR( + { XE_RTP_NAME("basic-1"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET(REGULAR_REG1, + REG_BIT(1) | REG_BIT(2), + REG_BIT(1) | REG_BIT(2))) + }, + /* drop: bits are not disjoint with previous entries */ + { XE_RTP_NAME("basic-2"), + XE_RTP_RULES(FUNC(match_yes)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(REGULAR_REG1, + REG_BIT(2) | REG_BIT(3), + bits_2_3_set)) + }, + ), }, { .name = "conflict-reg-type", @@ -432,7 +477,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0) | BIT(1) | BIT(2), .expected_count_sr_entries = 1, .expected_sr_errors = 2, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("basic-1"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(REGULAR_REG1, REG_BIT(0))) @@ -447,8 +492,7 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(MASKED_REG1, REG_BIT(0))) }, - {} - }, + ), }, { .name = "bad-mcr-reg-forced-to-regular", @@ -458,13 +502,12 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("bad-mcr-regular-reg"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(BAD_MCR_REG4, REG_BIT(0))) }, - {} - }, + ), }, { .name = "bad-regular-reg-forced-to-mcr", @@ -474,13 +517,12 @@ static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { .expected_active = BIT(0), .expected_count_sr_entries = 1, .expected_sr_errors = 1, - .entries = (const struct xe_rtp_entry_sr[]) { + .table = XE_RTP_TABLE_SR( { XE_RTP_NAME("bad-regular-reg"), XE_RTP_RULES(FUNC(match_yes)), XE_RTP_ACTIONS(SET(BAD_REGULAR_REG5, REG_BIT(0))) }, - {} - }, + ), }, }; @@ -492,16 +534,12 @@ static void xe_rtp_process_to_sr_tests(struct kunit *test) struct xe_reg_sr *reg_sr = >->reg_sr; const struct xe_reg_sr_entry *sre, *sr_entry = NULL; struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); - unsigned long idx, count_sr_entries = 0, count_rtp_entries = 0, active = 0; + unsigned long idx, count_sr_entries = 0, active = 0; xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe); - while (param->entries[count_rtp_entries].rules) - count_rtp_entries++; - - xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); - xe_rtp_process_to_sr(&ctx, param->entries, count_rtp_entries, - reg_sr, false); + xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries); + xe_rtp_process_to_sr(&ctx, ¶m->table, reg_sr, false); xa_for_each(®_sr->xa, idx, sre) { if (idx == param->expected_reg.addr) @@ -534,56 +572,52 @@ static const struct rtp_test_case rtp_cases[] = { { .name = "active1", .expected_active = BIT(0), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_yes)), }, - {} - }, + ), }, { .name = "active2", .expected_active = BIT(0) | BIT(1), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_yes)), }, { XE_RTP_NAME("r2"), XE_RTP_RULES(FUNC(match_yes)), }, - {} - }, + ), }, { .name = "active-inactive", .expected_active = BIT(0), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_yes)), }, { XE_RTP_NAME("r2"), XE_RTP_RULES(FUNC(match_no)), }, - {} - }, + ), }, { .name = "inactive-active", .expected_active = BIT(1), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_no)), }, { XE_RTP_NAME("r2"), XE_RTP_RULES(FUNC(match_yes)), }, - {} - }, + ), }, { .name = "inactive-active-inactive", .expected_active = BIT(1), - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_no)), }, @@ -593,13 +627,12 @@ static const struct rtp_test_case rtp_cases[] = { { XE_RTP_NAME("r3"), XE_RTP_RULES(FUNC(match_no)), }, - {} - }, + ), }, { .name = "inactive-inactive-inactive", .expected_active = 0, - .entries = (const struct xe_rtp_entry[]) { + .table = XE_RTP_TABLE( { XE_RTP_NAME("r1"), XE_RTP_RULES(FUNC(match_no)), }, @@ -609,8 +642,7 @@ static const struct rtp_test_case rtp_cases[] = { { XE_RTP_NAME("r3"), XE_RTP_RULES(FUNC(match_no)), }, - {} - }, + ), }, }; @@ -620,13 +652,10 @@ static void xe_rtp_process_tests(struct kunit *test) struct xe_device *xe = test->priv; struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); - unsigned long count_rtp_entries = 0, active = 0; + unsigned long active = 0; - while (param->entries[count_rtp_entries].rules) - count_rtp_entries++; - - xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); - xe_rtp_process(&ctx, param->entries); + xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, param->table.n_entries); + xe_rtp_process(&ctx, ¶m->table); KUNIT_EXPECT_EQ(test, active, param->expected_active); } diff --git a/drivers/gpu/drm/xe/tests/xe_wa_test.c b/drivers/gpu/drm/xe/tests/xe_wa_test.c index ff0e2502b39f..21601e9df353 100644 --- a/drivers/gpu/drm/xe/tests/xe_wa_test.c +++ b/drivers/gpu/drm/xe/tests/xe_wa_test.c @@ -43,9 +43,6 @@ static int xe_wa_test_init(struct kunit *test) xe_gt_mmio_init(gt); } - if (!param->graphics_verx100) - xe->info.step = param->step; - /* TODO: init hw engines for engine/LRC WAs */ xe->drm.dev = dev; test->priv = xe; diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 22b471303984..3c018dbccc07 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -117,7 +117,6 @@ static int info(struct seq_file *m, void *data) drm_printf(&p, "revid %d\n", xe->info.revid); drm_printf(&p, "tile_count %d\n", xe->info.tile_count); drm_printf(&p, "vm_max_level %d\n", xe->info.vm_max_level); - drm_printf(&p, "force_execlist %s\n", str_yes_no(xe->info.force_execlist)); drm_printf(&p, "has_flat_ccs %s\n", str_yes_no(xe->info.has_flat_ccs)); drm_printf(&p, "has_usm %s\n", str_yes_no(xe->info.has_usm)); drm_printf(&p, "skip_guc_pc %s\n", str_yes_no(xe->info.skip_guc_pc)); diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 4efd2bc8c02e..ad7f3e61d457 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -61,6 +61,7 @@ #include "xe_psmi.h" #include "xe_pxp.h" #include "xe_query.h" +#include "xe_ras.h" #include "xe_shrinker.h" #include "xe_soc_remapper.h" #include "xe_survivability_mode.h" @@ -738,9 +739,11 @@ static void vf_update_device_info(struct xe_device *xe) xe->info.probe_display = 0; xe->info.has_heci_cscfi = 0; xe->info.has_heci_gscfi = 0; + xe->info.has_i2c = 0; xe->info.has_late_bind = 0; xe->info.skip_guc_pc = 1; xe->info.skip_pcode = 1; + xe->info.has_drm_ras = false; } static int xe_device_vram_alloc(struct xe_device *xe) @@ -949,6 +952,15 @@ int xe_device_probe(struct xe_device *xe) return err; } + /* + * Wa_16029380221: The affected GT will always use non-coherent + * access to page tables, so we must do uncached writes from the + * CPU. + */ + for_each_gt(gt, xe, id) + if (XE_GT_WA(gt, 16029380221)) + xe->info.has_cached_pt = false; + for_each_tile(tile, xe, id) { err = xe_ggtt_init_early(tile->mem.ggtt); if (err) @@ -989,6 +1001,16 @@ int xe_device_probe(struct xe_device *xe) if (err) return err; + err = xe_soc_remapper_init(xe); + if (err) + return err; + + err = xe_sysctrl_init(xe); + if (err) + return err; + + xe_ras_init(xe); + /* * Now that GT is initialized (TTM in particular), * we can try to init display, and inherit the initial fb. @@ -1029,10 +1051,6 @@ int xe_device_probe(struct xe_device *xe) xe_nvm_init(xe); - err = xe_soc_remapper_init(xe); - if (err) - return err; - err = xe_heci_gsc_init(xe); if (err) return err; @@ -1071,10 +1089,6 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err_unregister_display; - err = xe_sysctrl_init(xe); - if (err) - goto err_unregister_display; - err = xe_device_sysfs_init(xe); if (err) goto err_unregister_display; @@ -1129,14 +1143,14 @@ void xe_device_shutdown(struct xe_device *xe) drm_dbg(&xe->drm, "Shutting down device\n"); - xe_display_pm_shutdown(xe); + xe_display_shutdown(xe); xe_irq_suspend(xe); for_each_gt(gt, xe, id) xe_gt_shutdown(gt); - xe_display_pm_shutdown_late(xe); + xe_display_shutdown_late(xe); if (!xe_driver_flr_disabled(xe)) { /* BOOM! */ diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index 975768a6a9c8..a03760d0ce38 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -116,7 +116,7 @@ static inline struct xe_mmio *xe_root_tile_mmio(struct xe_device *xe) static inline bool xe_device_uc_enabled(struct xe_device *xe) { - return !xe->info.force_execlist; + return true; } #define for_each_tile(tile__, xe__, id__) \ @@ -181,6 +181,21 @@ static inline bool xe_device_has_mert(const struct xe_device *xe) return xe->info.has_mert; } +static inline bool xe_device_is_in_reset(struct xe_device *xe) +{ + return atomic_read(&xe->in_reset); +} + +static inline void xe_device_set_in_reset(struct xe_device *xe) +{ + atomic_set(&xe->in_reset, 1); +} + +static inline void xe_device_clear_in_reset(struct xe_device *xe) +{ + atomic_set(&xe->in_reset, 0); +} + u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size); void xe_device_snapshot_print(struct xe_device *xe, struct drm_printer *p); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 32dd2ffbc796..022e08205897 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -144,8 +144,6 @@ struct xe_device { * Keep all flags below alphabetically sorted */ - /** @info.force_execlist: Forced execlist submission */ - u8 force_execlist:1; /** @info.has_access_counter: Device supports access counter */ u8 has_access_counter:1; /** @info.has_asid: Has address space ID */ @@ -156,6 +154,8 @@ struct xe_device { u8 has_cached_pt:1; /** @info.has_device_atomics_on_smem: Supports device atomics on SMEM */ u8 has_device_atomics_on_smem:1; + /** @info.has_drm_ras: Device supports drm_ras (Reliability, Availability, Serviceability) */ + u8 has_drm_ras:1; /** @info.has_fan_control: Device supports fan control */ u8 has_fan_control:1; /** @info.has_flat_ccs: Whether flat CCS metadata is used */ @@ -483,6 +483,9 @@ struct xe_device { /** @needs_flr_on_fini: requests function-reset on fini */ bool needs_flr_on_fini; + /** @in_reset: Indicates if device is in reset */ + atomic_t in_reset; + /** @wedged: Struct to control Wedged States and mode */ struct { /** @wedged.flag: Xe device faced a critical error and is now blocked. */ @@ -495,6 +498,9 @@ struct xe_device { bool inconsistent_reset; } wedged; + /** @devres_group: devres group */ + void *devres_group; + /** @bo_device: Struct to control async free of BOs */ struct xe_bo_dev { /** @bo_device.async_free: Free worker */ diff --git a/drivers/gpu/drm/xe/xe_drm_client.c b/drivers/gpu/drm/xe/xe_drm_client.c index 84b66147bf49..e116fb562c4c 100644 --- a/drivers/gpu/drm/xe/xe_drm_client.c +++ b/drivers/gpu/drm/xe/xe_drm_client.c @@ -168,10 +168,20 @@ static void bo_meminfo(struct xe_bo *bo, struct drm_memory_stats stats[TTM_NUM_MEM_TYPES]) { u64 sz = xe_bo_size(bo); - u32 mem_type = bo->ttm.resource->mem_type; + u32 mem_type; xe_bo_assert_held(bo); + /* + * The resource can be NULL if the BO has been purged, plus maybe some + * other cases. Either way there shouldn't be any memory to account for, + * or a current resource to account this against, so skip for now. + */ + if (!bo->ttm.resource) + return; + + mem_type = bo->ttm.resource->mem_type; + if (drm_gem_object_is_shared_for_memory_stats(&bo->ttm.base)) stats[mem_type].shared += sz; else @@ -183,7 +193,7 @@ static void bo_meminfo(struct xe_bo *bo, if (!dma_resv_test_signaled(bo->ttm.base.resv, DMA_RESV_USAGE_BOOKKEEP)) stats[mem_type].active += sz; - else if (mem_type == XE_PL_SYSTEM) + else if (mem_type == XE_PL_SYSTEM || xe_bo_madv_is_dontneed(bo)) stats[mem_type].purgeable += sz; } } @@ -263,8 +273,7 @@ static void show_meminfo(struct drm_printer *p, struct drm_file *file) &stats[mem_type], DRM_GEM_OBJECT_ACTIVE | DRM_GEM_OBJECT_RESIDENT | - (mem_type != XE_PL_SYSTEM ? 0 : - DRM_GEM_OBJECT_PURGEABLE), + DRM_GEM_OBJECT_PURGEABLE, xe_mem_type_to_name[mem_type]); } } diff --git a/drivers/gpu/drm/xe/xe_drm_ras.c b/drivers/gpu/drm/xe/xe_drm_ras.c index cd236f53699e..7937d8ba0ed9 100644 --- a/drivers/gpu/drm/xe/xe_drm_ras.c +++ b/drivers/gpu/drm/xe/xe_drm_ras.c @@ -11,27 +11,46 @@ #include "xe_device_types.h" #include "xe_drm_ras.h" +#include "xe_ras.h" static const char * const error_components[] = DRM_XE_RAS_ERROR_COMPONENT_NAMES; static const char * const error_severity[] = DRM_XE_RAS_ERROR_SEVERITY_NAMES; -static int hw_query_error_counter(struct xe_drm_ras_counter *info, - u32 error_id, const char **name, u32 *val) +static int query_error_counter(struct xe_device *xe, + enum drm_xe_ras_error_severity severity, + u32 error_id, const char **name, u32 *val) { + struct xe_drm_ras *ras = &xe->ras; + struct xe_drm_ras_counter *info = ras->info[severity]; + if (!info || !info[error_id].name) return -ENOENT; *name = info[error_id].name; + + /* Fetch counter from system controller if supported */ + if (xe->info.has_sysctrl) + return xe_ras_get_counter(xe, severity, error_id, val); + *val = atomic_read(&info[error_id].counter); return 0; } -static int hw_clear_error_counter(struct xe_drm_ras_counter *info, u32 error_id) +static int clear_error_counter(struct xe_device *xe, + enum drm_xe_ras_error_severity severity, + u32 error_id) { + struct xe_drm_ras *ras = &xe->ras; + struct xe_drm_ras_counter *info = ras->info[severity]; + if (!info || !info[error_id].name) return -ENOENT; + /* Clear counter from system controller if supported */ + if (xe->info.has_sysctrl) + return xe_ras_clear_counter(xe, severity, error_id); + atomic_set(&info[error_id].counter, 0); return 0; @@ -41,38 +60,30 @@ static int query_uncorrectable_error_counter(struct drm_ras_node *ep, u32 error_ const char **name, u32 *val) { struct xe_device *xe = ep->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_UNCORRECTABLE]; - return hw_query_error_counter(info, error_id, name, val); + return query_error_counter(xe, DRM_XE_RAS_ERR_SEV_UNCORRECTABLE, error_id, name, val); } static int clear_uncorrectable_error_counter(struct drm_ras_node *node, u32 error_id) { struct xe_device *xe = node->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_UNCORRECTABLE]; - return hw_clear_error_counter(info, error_id); + return clear_error_counter(xe, DRM_XE_RAS_ERR_SEV_UNCORRECTABLE, error_id); } static int query_correctable_error_counter(struct drm_ras_node *ep, u32 error_id, const char **name, u32 *val) { struct xe_device *xe = ep->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_CORRECTABLE]; - return hw_query_error_counter(info, error_id, name, val); + return query_error_counter(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id, name, val); } static int clear_correctable_error_counter(struct drm_ras_node *node, u32 error_id) { struct xe_device *xe = node->priv; - struct xe_drm_ras *ras = &xe->ras; - struct xe_drm_ras_counter *info = ras->info[DRM_XE_RAS_ERR_SEV_CORRECTABLE]; - return hw_clear_error_counter(info, error_id); + return clear_error_counter(xe, DRM_XE_RAS_ERR_SEV_CORRECTABLE, error_id); } static struct xe_drm_ras_counter *allocate_and_copy_counters(struct xe_device *xe) diff --git a/drivers/gpu/drm/xe/xe_eu_stall.c b/drivers/gpu/drm/xe/xe_eu_stall.c index 297be3c42b20..d37770c58c5d 100644 --- a/drivers/gpu/drm/xe/xe_eu_stall.c +++ b/drivers/gpu/drm/xe/xe_eu_stall.c @@ -985,9 +985,10 @@ int xe_eu_stall_stream_open(struct drm_device *dev, u64 data, struct drm_file *f return -ENODEV; } - if (xe_observation_paranoid && !perfmon_capable()) { + ret = xe_observation_paranoid_check(); + if (ret) { drm_dbg(&xe->drm, "Insufficient privileges for EU stall monitoring\n"); - return -EACCES; + return ret; } /* Initialize and set default values */ diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 2f5ccf294675..d27ce24daae5 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -318,8 +318,6 @@ struct xe_exec_queue_ops { void (*resume)(struct xe_exec_queue *q); /** @reset_status: check exec queue reset status */ bool (*reset_status)(struct xe_exec_queue *q); - /** @active: check exec queue is active */ - bool (*active)(struct xe_exec_queue *q); }; #endif diff --git a/drivers/gpu/drm/xe/xe_execlist.c b/drivers/gpu/drm/xe/xe_execlist.c index 9fb99c038ea8..6b86b4f9cc1c 100644 --- a/drivers/gpu/drm/xe/xe_execlist.c +++ b/drivers/gpu/drm/xe/xe_execlist.c @@ -458,12 +458,6 @@ static bool execlist_exec_queue_reset_status(struct xe_exec_queue *q) return false; } -static bool execlist_exec_queue_active(struct xe_exec_queue *q) -{ - /* NIY */ - return false; -} - static const struct xe_exec_queue_ops execlist_exec_queue_ops = { .init = execlist_exec_queue_init, .kill = execlist_exec_queue_kill, @@ -476,7 +470,6 @@ static const struct xe_exec_queue_ops execlist_exec_queue_ops = { .suspend_wait = execlist_exec_queue_suspend_wait, .resume = execlist_exec_queue_resume, .reset_status = execlist_exec_queue_reset_status, - .active = execlist_exec_queue_active, }; int xe_execlist_init(struct xe_gt *gt) diff --git a/drivers/gpu/drm/xe/xe_ggtt.c b/drivers/gpu/drm/xe/xe_ggtt.c index a351c578b170..8ec23862477f 100644 --- a/drivers/gpu/drm/xe/xe_ggtt.c +++ b/drivers/gpu/drm/xe/xe_ggtt.c @@ -111,14 +111,14 @@ struct xe_ggtt_pt_ops { struct xe_ggtt { /** @tile: Back pointer to tile where this GGTT belongs */ struct xe_tile *tile; - /** @start: Start offset of GGTT */ + /** @start: Start offset of GGTT */ u64 start; /** @size: Total usable size of this GGTT */ u64 size; - /** - * @flags: Flags for this GGTT + * @flags: Flags for this GGTT. * Acceptable flags: + * * - %XE_GGTT_FLAGS_64K - if PTE size is 64K. Otherwise, regular is 4K. * - %XE_GGTT_FLAGS_ONLINE - is GGTT online, protected by ggtt->lock * after init @@ -129,7 +129,7 @@ struct xe_ggtt { /** @lock: Mutex lock to protect GGTT data */ struct mutex lock; /** - * @gsm: The iomem pointer to the actual location of the translation + * @gsm: The iomem pointer to the actual location of the translation * table located in the GSM for easy PTE manipulation */ u64 __iomem *gsm; diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 783eb6d631b5..d904527a8898 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -917,6 +917,9 @@ static void gt_reset_worker(struct work_struct *w) if (xe_device_wedged(gt_to_xe(gt))) goto err_pm_put; + if (xe_device_is_in_reset(gt_to_xe(gt))) + goto err_pm_put; + /* We only support GT resets with GuC submission */ if (!xe_device_uc_enabled(gt_to_xe(gt))) goto err_pm_put; @@ -977,18 +980,21 @@ static void gt_reset_worker(struct work_struct *w) void xe_gt_reset_async(struct xe_gt *gt) { - xe_gt_info(gt, "trying reset from %ps\n", __builtin_return_address(0)); + struct xe_device *xe = gt_to_xe(gt); + + if (xe_device_is_in_reset(xe)) + return; /* Don't do a reset while one is already in flight */ if (!xe_fault_inject_gt_reset() && xe_uc_reset_prepare(>->uc)) return; - xe_gt_info(gt, "reset queued\n"); + xe_gt_info(gt, "reset queued from %ps\n", __builtin_return_address(0)); /* Pair with put in gt_reset_worker() if work is enqueued */ - xe_pm_runtime_get_noresume(gt_to_xe(gt)); + xe_pm_runtime_get_noresume(xe); if (!queue_work(gt->ordered_wq, >->reset.worker)) - xe_pm_runtime_put(gt_to_xe(gt)); + xe_pm_runtime_put(xe); } void xe_gt_suspend_prepare(struct xe_gt *gt) diff --git a/drivers/gpu/drm/xe/xe_gt_debugfs.c b/drivers/gpu/drm/xe/xe_gt_debugfs.c index f45306308cd6..c38bcacb27e4 100644 --- a/drivers/gpu/drm/xe/xe_gt_debugfs.c +++ b/drivers/gpu/drm/xe/xe_gt_debugfs.c @@ -149,8 +149,10 @@ static int register_save_restore(struct xe_gt *gt, struct drm_printer *p) drm_printf(p, "\n"); drm_printf(p, "Whitelist\n"); - for_each_hw_engine(hwe, gt, id) + for_each_hw_engine(hwe, gt, id) { xe_reg_whitelist_dump(&hwe->reg_whitelist, p); + xe_reg_whitelist_dump(&hwe->oa_whitelist, p); + } return 0; } diff --git a/drivers/gpu/drm/xe/xe_gt_mcr.c b/drivers/gpu/drm/xe/xe_gt_mcr.c index 04f0098070a4..a97b236dab7c 100644 --- a/drivers/gpu/drm/xe/xe_gt_mcr.c +++ b/drivers/gpu/drm/xe/xe_gt_mcr.c @@ -404,8 +404,7 @@ static unsigned int dss_per_group(struct xe_gt *gt) * Some older platforms don't have tables or don't have complete tables. * Newer platforms should always have the required info. */ - if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 2000 && - !gt_to_xe(gt)->info.force_execlist) + if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 2000) xe_gt_err(gt, "Slice/Subslice counts missing from hwconfig table; using typical fallback values\n"); if (gt_to_xe(gt)->info.platform == XE_PVC) @@ -507,7 +506,7 @@ void xe_gt_mcr_init_early(struct xe_gt *gt) spin_lock_init(>->mcr_lock); if (gt->info.type == XE_GT_TYPE_MEDIA) { - drm_WARN_ON(&xe->drm, MEDIA_VER(xe) < 13); + xe_gt_WARN_ON(gt, MEDIA_VER(xe) < 13); if (MEDIA_VER(xe) >= 30) { gt->steering[OADDRM].ranges = xe2lpm_gpmxmt_steering_table; @@ -662,9 +661,9 @@ bool xe_gt_mcr_get_nonterminated_steering(struct xe_gt *gt, for (int type = 0; type < IMPLICIT_STEERING; type++) { if (reg_in_steering_type_ranges(gt, reg, type)) { - drm_WARN(>_to_xe(gt)->drm, !gt->steering[type].initialized, - "Uninitialized usage of MCR register %s/%#x\n", - xe_steering_types[type].name, reg.addr); + xe_gt_WARN(gt, !gt->steering[type].initialized, + "Uninitialized usage of MCR register %s/%#x\n", + xe_steering_types[type].name, reg.addr); *group = gt->steering[type].group_target; *instance = gt->steering[type].instance_target; @@ -679,9 +678,9 @@ bool xe_gt_mcr_get_nonterminated_steering(struct xe_gt *gt, * Not found in a steering table and not a register with implicit * steering. Just steer to 0/0 as a guess and raise a warning. */ - drm_WARN(>_to_xe(gt)->drm, true, - "Did not find MCR register %#x in any MCR steering table\n", - reg.addr); + xe_gt_WARN(gt, true, + "Did not find MCR register %#x in any MCR steering table\n", + reg.addr); *group = 0; *instance = 0; @@ -710,7 +709,7 @@ static void mcr_lock(struct xe_gt *gt) __acquires(>->mcr_lock) ret = xe_mmio_wait32(>->mmio, STEER_SEMAPHORE, 0x1, 0x1, 10, NULL, true); - drm_WARN_ON_ONCE(&xe->drm, ret == -ETIMEDOUT); + xe_gt_WARN_ON_ONCE(gt, ret == -ETIMEDOUT); } static void mcr_unlock(struct xe_gt *gt) __releases(>->mcr_lock) diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index 577a315854af..eed0a750d2eb 100644 --- a/drivers/gpu/drm/xe/xe_guc_relay.c +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -689,12 +689,17 @@ static int relay_action_handler(struct xe_guc_relay *relay, u32 origin, return relay_testloop_action_handler(relay, origin, msg, len, response, size); type = FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]); + relay_assert(relay, guc_hxg_type_is_action(type)); - if (IS_SRIOV_PF(relay_to_xe(relay))) - ret = xe_gt_sriov_pf_service_process_request(gt, origin, msg, len, response, size); - else + if (IS_SRIOV_PF(relay_to_xe(relay))) { + if (type == GUC_HXG_TYPE_REQUEST) + ret = xe_gt_sriov_pf_service_process_request(gt, origin, msg, len, + response, size); + else + ret = -EOPNOTSUPP; + } else { ret = -EOPNOTSUPP; - + } if (type == GUC_HXG_TYPE_EVENT) relay_assert(relay, ret <= 0); diff --git a/drivers/gpu/drm/xe/xe_guc_submit.c b/drivers/gpu/drm/xe/xe_guc_submit.c index 12a410458df6..12416bfa3255 100644 --- a/drivers/gpu/drm/xe/xe_guc_submit.c +++ b/drivers/gpu/drm/xe/xe_guc_submit.c @@ -1163,7 +1163,7 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job) if (exec_queue_suspended(q)) return; - if (!exec_queue_enabled(q) && !exec_queue_suspended(q)) { + if (!exec_queue_enabled(q)) { action[len++] = XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET; action[len++] = q->guc->id; action[len++] = GUC_CONTEXT_ENABLE; @@ -1493,7 +1493,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) struct xe_device *xe = guc_to_xe(guc); int err = -ETIME; pid_t pid = -1; - bool wedged = false, skip_timeout_check; + bool wedged = false, wedge_device = false, skip_timeout_check; xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q)); @@ -1532,7 +1532,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) * If devcoredump not captured and GuC capture for the job is not ready * do manual capture first and decide later if we need to use it */ - if (!exec_queue_killed(q) && !xe->devcoredump.captured && + if (!xe_device_is_in_reset(xe) && !exec_queue_killed(q) && !xe->devcoredump.captured && !xe_guc_capture_get_matching_and_lock(q)) { /* take force wake before engine register manual capture */ CLASS(xe_force_wake, fw_ref)(gt_to_fw(q->gt), XE_FORCEWAKE_ALL); @@ -1554,8 +1554,8 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) set_exec_queue_banned(q); /* Kick job / queue off hardware */ - if (!wedged && (exec_queue_enabled(primary) || - exec_queue_pending_disable(primary))) { + if (!xe_device_is_in_reset(xe) && !wedged && + (exec_queue_enabled(primary) || exec_queue_pending_disable(primary))) { int ret; if (exec_queue_reset(primary)) @@ -1623,7 +1623,8 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) trace_xe_sched_job_timedout(job); - if (!exec_queue_killed(q)) + /* Do not access device if in reset */ + if (!xe_device_is_in_reset(xe) && !exec_queue_killed(q)) xe_devcoredump(q, job, "Timedout job - seqno=%u, lrc_seqno=%u, guc_id=%d, flags=0x%lx", xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), @@ -1638,7 +1639,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) } if (q->flags & EXEC_QUEUE_FLAG_KERNEL) { xe_gt_WARN(q->gt, true, "Kernel-submitted job timed out\n"); - xe_device_declare_wedged(gt_to_xe(q->gt)); + wedge_device = true; } } else if (q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)) { xe_gt_WARN(q->gt, true, "VM job timed out on non-killed execqueue\n"); @@ -1658,6 +1659,9 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) xe_guc_exec_queue_trigger_cleanup(q); } + if (wedge_device) + xe_device_declare_wedged(gt_to_xe(q->gt)); + /* * We want the job added back to the pending list so it gets freed; this * is what DRM_GPU_SCHED_STAT_NO_HANG does. @@ -2241,14 +2245,6 @@ static bool guc_exec_queue_reset_status(struct xe_exec_queue *q) return exec_queue_reset(q) || exec_queue_killed_or_banned_or_wedged(q); } -static bool guc_exec_queue_active(struct xe_exec_queue *q) -{ - struct xe_exec_queue *primary = xe_exec_queue_multi_queue_primary(q); - - return exec_queue_enabled(primary) && - !exec_queue_pending_disable(primary); -} - /* * All of these functions are an abstraction layer which other parts of Xe can * use to trap into the GuC backend. All of these functions, aside from init, @@ -2268,7 +2264,6 @@ static const struct xe_exec_queue_ops guc_exec_queue_ops = { .suspend_wait = guc_exec_queue_suspend_wait, .resume = guc_exec_queue_resume, .reset_status = guc_exec_queue_reset_status, - .active = guc_exec_queue_active, }; static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q) diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c index cf6d106e6036..046d0655122f 100644 --- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c +++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c @@ -208,9 +208,6 @@ static int send_tlb_inval_asid_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, lockdep_assert_held(&tlb_inval->seqno_lock); - if (guc_to_xe(guc)->info.force_execlist) - return -ECANCELED; - return send_tlb_inval_ppgtt(guc, seqno, start, end, asid, XE_GUC_TLB_INVAL_PAGE_SELECTIVE, prl_sa); } @@ -228,9 +225,6 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, lockdep_assert_held(&tlb_inval->seqno_lock); - if (xe->info.force_execlist) - return -ECANCELED; - vm = xe_device_asid_to_vm(xe, asid); if (IS_ERR(vm)) return PTR_ERR(vm); diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index 8c66ff6f3d3c..87d60c4117bd 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -337,42 +337,43 @@ static bool xe_rtp_cfeg_wmtp_disabled(const struct xe_device *xe, return xe_mmio_read32(&hwe->gt->mmio, XEHP_FUSE4) & CFEG_WMTP_DISABLE; } +static u32 blit_cctl_val(struct xe_gt *gt, struct xe_hw_engine *hwe) +{ + return REG_FIELD_PREP(BLIT_CCTL_DST_MOCS_MASK, gt->mocs.uc_index) | + REG_FIELD_PREP(BLIT_CCTL_SRC_MOCS_MASK, gt->mocs.uc_index); +} + +static const struct xe_rtp_table_sr lrc_setup = XE_RTP_TABLE_SR( + /* + * Some blitter commands do not have a field for MOCS, those + * commands will use MOCS index pointed by BLIT_CCTL. + * BLIT_CCTL registers are needed to be programmed to un-cached. + */ + { XE_RTP_NAME("BLIT_CCTL_default_MOCS"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1274), + ENGINE_CLASS(COPY)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(BLIT_CCTL(0), + BLIT_CCTL_DST_MOCS_MASK | + BLIT_CCTL_SRC_MOCS_MASK, + blit_cctl_val, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + /* Disable WMTP if HW doesn't support it */ + { XE_RTP_NAME("DISABLE_WMTP_ON_UNSUPPORTED_HW"), + XE_RTP_RULES(FUNC(xe_rtp_cfeg_wmtp_disabled)), + XE_RTP_ACTIONS(FIELD_SET(CS_CHICKEN1(0), + PREEMPT_GPGPU_LEVEL_MASK, + PREEMPT_GPGPU_THREAD_GROUP_LEVEL)), + XE_RTP_ENTRY_FLAG(FOREACH_ENGINE) + }, +); + static void hw_engine_setup_default_lrc_state(struct xe_hw_engine *hwe) { - struct xe_gt *gt = hwe->gt; - const u8 mocs_write_idx = gt->mocs.uc_index; - const u8 mocs_read_idx = gt->mocs.uc_index; - u32 blit_cctl_val = REG_FIELD_PREP(BLIT_CCTL_DST_MOCS_MASK, mocs_write_idx) | - REG_FIELD_PREP(BLIT_CCTL_SRC_MOCS_MASK, mocs_read_idx); struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); - const struct xe_rtp_entry_sr lrc_setup[] = { - /* - * Some blitter commands do not have a field for MOCS, those - * commands will use MOCS index pointed by BLIT_CCTL. - * BLIT_CCTL registers are needed to be programmed to un-cached. - */ - { XE_RTP_NAME("BLIT_CCTL_default_MOCS"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1274), - ENGINE_CLASS(COPY)), - XE_RTP_ACTIONS(FIELD_SET(BLIT_CCTL(0), - BLIT_CCTL_DST_MOCS_MASK | - BLIT_CCTL_SRC_MOCS_MASK, - blit_cctl_val, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - /* Disable WMTP if HW doesn't support it */ - { XE_RTP_NAME("DISABLE_WMTP_ON_UNSUPPORTED_HW"), - XE_RTP_RULES(FUNC(xe_rtp_cfeg_wmtp_disabled)), - XE_RTP_ACTIONS(FIELD_SET(CS_CHICKEN1(0), - PREEMPT_GPGPU_LEVEL_MASK, - PREEMPT_GPGPU_THREAD_GROUP_LEVEL)), - XE_RTP_ENTRY_FLAG(FOREACH_ENGINE) - }, - }; - xe_rtp_process_to_sr(&ctx, lrc_setup, ARRAY_SIZE(lrc_setup), - &hwe->reg_lrc, true); + xe_rtp_process_to_sr(&ctx, &lrc_setup, &hwe->reg_lrc, true); } void xe_hw_engine_setup_reg_lrc(struct xe_hw_engine *hwe) @@ -386,89 +387,94 @@ void xe_hw_engine_setup_reg_lrc(struct xe_hw_engine *hwe) xe_tuning_process_lrc(hwe); } +/* + * RING_CMD_CCTL specifies the default MOCS entry that will be + * used by the command streamer when executing commands that + * don't have a way to explicitly specify a MOCS setting. + * The default should usually reference whichever MOCS entry + * corresponds to uncached behavior, although use of a WB cached + * entry is recommended by the spec in certain circumstances on + * specific platforms. + * Bspec: 72161 + */ +static u32 ring_cmd_cctl_val(struct xe_gt *gt, struct xe_hw_engine *hwe) +{ + struct xe_device *xe = gt_to_xe(gt); + u8 mocs_read_idx = gt->mocs.uc_index; + + if (hwe->class == XE_ENGINE_CLASS_COMPUTE && IS_DGFX(xe) && + (GRAPHICS_VER(xe) >= 20 || xe->info.platform == XE_PVC)) + mocs_read_idx = gt->mocs.wb_index; + + return REG_FIELD_PREP(CMD_CCTL_WRITE_OVERRIDE_MASK, gt->mocs.uc_index) | + REG_FIELD_PREP(CMD_CCTL_READ_OVERRIDE_MASK, mocs_read_idx); +} + +static const struct xe_rtp_table_sr engine_sr = XE_RTP_TABLE_SR( + { XE_RTP_NAME("RING_CMD_CCTL_default_MOCS"), + XE_RTP_RULES(FUNC(xe_rtp_match_always)), + XE_RTP_ACTIONS(FIELD_SET_FUNC(RING_CMD_CCTL(0), + CMD_CCTL_WRITE_OVERRIDE_MASK | + CMD_CCTL_READ_OVERRIDE_MASK, + ring_cmd_cctl_val, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + { XE_RTP_NAME("Disable HW status page updates for interrupts"), + XE_RTP_RULES(FUNC(xe_rtp_match_always)), + XE_RTP_ACTIONS(SET(RING_HWSTAM(0), ~0x0, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + { XE_RTP_NAME("Disable engine 'legacy' mode"), + XE_RTP_RULES(FUNC(xe_rtp_match_always)), + XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_DISABLE_LEGACY_MODE, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + /* + * To allow the GSC engine to go idle on MTL we need to enable + * idle messaging and set the hysteresis value (we use 0xA=5us + * as recommended in spec). On platforms after MTL this is + * enabled by default. + */ + { XE_RTP_NAME("MTL GSCCS IDLE MSG enable"), + XE_RTP_RULES(MEDIA_VERSION(1300), ENGINE_CLASS(OTHER)), + XE_RTP_ACTIONS(CLR(RING_PSMI_CTL(0), + IDLE_MSG_DISABLE, + XE_RTP_ACTION_FLAG(ENGINE_BASE)), + FIELD_SET(RING_PWRCTX_MAXCNT(0), + IDLE_WAIT_TIME, + 0xA, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + /* Enable Priority Mem Read */ + { XE_RTP_NAME("Priority_Mem_Read"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, XE_RTP_END_VERSION_UNDEFINED)), + XE_RTP_ACTIONS(SET(CSFE_CHICKEN1(0), CS_PRIORITY_MEM_READ, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, + { XE_RTP_NAME("Enable CCS Engine(s)"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1255, XE_RTP_END_VERSION_UNDEFINED), + FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_ACTIONS(SET(RCU_MODE, RCU_MODE_CCS_ENABLE)) + }, + /* Use Fixed slice CCS mode */ + { XE_RTP_NAME("RCU_MODE_FIXED_SLICE_CCS_MODE"), + XE_RTP_RULES(FUNC(xe_hw_engine_match_fixed_cslice_mode)), + XE_RTP_ACTIONS(FIELD_SET(RCU_MODE, RCU_MODE_FIXED_SLICE_CCS_MODE, + RCU_MODE_FIXED_SLICE_CCS_MODE)) + }, + { XE_RTP_NAME("Enable MSI-X interrupt support"), + XE_RTP_RULES(FUNC(xe_rtp_match_has_msix)), + XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_MSIX_INTERRUPT_ENABLE, + XE_RTP_ACTION_FLAG(ENGINE_BASE))) + }, +); + static void hw_engine_setup_default_state(struct xe_hw_engine *hwe) { - struct xe_gt *gt = hwe->gt; - struct xe_device *xe = gt_to_xe(gt); - /* - * RING_CMD_CCTL specifies the default MOCS entry that will be - * used by the command streamer when executing commands that - * don't have a way to explicitly specify a MOCS setting. - * The default should usually reference whichever MOCS entry - * corresponds to uncached behavior, although use of a WB cached - * entry is recommended by the spec in certain circumstances on - * specific platforms. - * Bspec: 72161 - */ - const u8 mocs_write_idx = gt->mocs.uc_index; - const u8 mocs_read_idx = hwe->class == XE_ENGINE_CLASS_COMPUTE && IS_DGFX(xe) && - (GRAPHICS_VER(xe) >= 20 || xe->info.platform == XE_PVC) ? - gt->mocs.wb_index : gt->mocs.uc_index; - u32 ring_cmd_cctl_val = REG_FIELD_PREP(CMD_CCTL_WRITE_OVERRIDE_MASK, mocs_write_idx) | - REG_FIELD_PREP(CMD_CCTL_READ_OVERRIDE_MASK, mocs_read_idx); struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); - const struct xe_rtp_entry_sr engine_entries[] = { - { XE_RTP_NAME("RING_CMD_CCTL_default_MOCS"), - XE_RTP_RULES(FUNC(xe_rtp_match_always)), - XE_RTP_ACTIONS(FIELD_SET(RING_CMD_CCTL(0), - CMD_CCTL_WRITE_OVERRIDE_MASK | - CMD_CCTL_READ_OVERRIDE_MASK, - ring_cmd_cctl_val, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - { XE_RTP_NAME("Disable HW status page updates for interrupts"), - XE_RTP_RULES(FUNC(xe_rtp_match_always)), - XE_RTP_ACTIONS(SET(RING_HWSTAM(0), ~0x0, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - { XE_RTP_NAME("Disable engine 'legacy' mode"), - XE_RTP_RULES(FUNC(xe_rtp_match_always)), - XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_DISABLE_LEGACY_MODE, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - /* - * To allow the GSC engine to go idle on MTL we need to enable - * idle messaging and set the hysteresis value (we use 0xA=5us - * as recommended in spec). On platforms after MTL this is - * enabled by default. - */ - { XE_RTP_NAME("MTL GSCCS IDLE MSG enable"), - XE_RTP_RULES(MEDIA_VERSION(1300), ENGINE_CLASS(OTHER)), - XE_RTP_ACTIONS(CLR(RING_PSMI_CTL(0), - IDLE_MSG_DISABLE, - XE_RTP_ACTION_FLAG(ENGINE_BASE)), - FIELD_SET(RING_PWRCTX_MAXCNT(0), - IDLE_WAIT_TIME, - 0xA, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - /* Enable Priority Mem Read */ - { XE_RTP_NAME("Priority_Mem_Read"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, XE_RTP_END_VERSION_UNDEFINED)), - XE_RTP_ACTIONS(SET(CSFE_CHICKEN1(0), CS_PRIORITY_MEM_READ, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - { XE_RTP_NAME("Enable CCS Engine(s)"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1255, XE_RTP_END_VERSION_UNDEFINED), - FUNC(xe_rtp_match_first_render_or_compute)), - XE_RTP_ACTIONS(SET(RCU_MODE, RCU_MODE_CCS_ENABLE)) - }, - /* Use Fixed slice CCS mode */ - { XE_RTP_NAME("RCU_MODE_FIXED_SLICE_CCS_MODE"), - XE_RTP_RULES(FUNC(xe_hw_engine_match_fixed_cslice_mode)), - XE_RTP_ACTIONS(FIELD_SET(RCU_MODE, RCU_MODE_FIXED_SLICE_CCS_MODE, - RCU_MODE_FIXED_SLICE_CCS_MODE)) - }, - { XE_RTP_NAME("Enable MSI-X interrupt support"), - XE_RTP_RULES(FUNC(xe_rtp_match_has_msix)), - XE_RTP_ACTIONS(SET(GFX_MODE(0), GFX_MSIX_INTERRUPT_ENABLE, - XE_RTP_ACTION_FLAG(ENGINE_BASE))) - }, - }; - xe_rtp_process_to_sr(&ctx, engine_entries, ARRAY_SIZE(engine_entries), - &hwe->reg_sr, false); + xe_rtp_process_to_sr(&ctx, &engine_sr, &hwe->reg_sr, false); } static const struct engine_info *find_engine_info(enum xe_engine_class class, int instance) @@ -574,6 +580,8 @@ static void hw_engine_init_early(struct xe_gt *gt, struct xe_hw_engine *hwe, hw_engine_setup_default_state(hwe); xe_reg_sr_init(&hwe->reg_whitelist, hwe->name, gt_to_xe(gt)); + xe_reg_sr_init(&hwe->oa_whitelist, hwe->name, gt_to_xe(gt)); + xe_reg_sr_init(&hwe->oa_sr, hwe->name, gt_to_xe(gt)); xe_reg_whitelist_process_engine(hwe); } @@ -628,7 +636,7 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe, hwe->exl_port = xe_execlist_port_create(xe, hwe); if (IS_ERR(hwe->exl_port)) { err = PTR_ERR(hwe->exl_port); - goto err_hwsp; + goto err_name; } } else { /* GSCCS has a special interrupt for reset */ @@ -648,8 +656,6 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe, return devm_add_action_or_reset(xe->drm.dev, hw_engine_fini, hwe); -err_hwsp: - xe_bo_unpin_map_no_vm(hwe->hwsp); err_name: hwe->name = NULL; diff --git a/drivers/gpu/drm/xe/xe_hw_engine_types.h b/drivers/gpu/drm/xe/xe_hw_engine_types.h index 2cf898e682f5..84c097da9b6f 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine_types.h +++ b/drivers/gpu/drm/xe/xe_hw_engine_types.h @@ -130,6 +130,14 @@ struct xe_hw_engine { * @reg_whitelist: table with registers to be whitelisted */ struct xe_reg_sr reg_whitelist; + /** + * @oa_whitelist: oa registers to be whitelisted + */ + struct xe_reg_sr oa_whitelist; + /** + * @oa_sr: oa nonpriv whitelist registers, changed on oa stream open/close + */ + struct xe_reg_sr oa_sr; /** * @reg_lrc: LRC workaround registers */ diff --git a/drivers/gpu/drm/xe/xe_hw_error.c b/drivers/gpu/drm/xe/xe_hw_error.c index 4b72959b2276..4a4b363fc844 100644 --- a/drivers/gpu/drm/xe/xe_hw_error.c +++ b/drivers/gpu/drm/xe/xe_hw_error.c @@ -437,6 +437,16 @@ static void hw_error_source_handler(struct xe_tile *tile, const enum hardware_er if (!IS_DGFX(xe)) return; + /* + * Hardware errors are reported through System Controller on the platforms that + * support it, and never routed as direct IRQ to SGUnit. So we should never be + * here for those platforms. + */ + if (xe->info.has_sysctrl) { + drm_err_ratelimited(&xe->drm, HW_ERR "Invalid error routing\n"); + return; + } + spin_lock_irqsave(&xe->irq.lock, flags); err_src = xe_mmio_read32(&tile->mmio, DEV_ERR_STAT_REG(hw_err)); if (!err_src) { @@ -516,14 +526,6 @@ void xe_hw_error_irq_handler(struct xe_tile *tile, const u32 master_ctl) } } -static int hw_error_info_init(struct xe_device *xe) -{ - if (xe->info.platform != XE_PVC) - return 0; - - return xe_drm_ras_init(xe); -} - /* * Process hardware errors during boot */ @@ -550,16 +552,11 @@ static void process_hw_errors(struct xe_device *xe) void xe_hw_error_init(struct xe_device *xe) { struct xe_tile *tile = xe_device_get_root_tile(xe); - int ret; if (!IS_DGFX(xe) || IS_SRIOV_VF(xe)) return; INIT_WORK(&tile->csc_hw_error_work, csc_hw_error_work); - ret = hw_error_info_init(xe); - if (ret) - drm_err(&xe->drm, "Failed to initialize XE DRM RAS (%pe)\n", ERR_PTR(ret)); - process_hw_errors(xe); } diff --git a/drivers/gpu/drm/xe/xe_i2c.c b/drivers/gpu/drm/xe/xe_i2c.c index 706783863d07..bd956776b10b 100644 --- a/drivers/gpu/drm/xe/xe_i2c.c +++ b/drivers/gpu/drm/xe/xe_i2c.c @@ -334,9 +334,6 @@ int xe_i2c_probe(struct xe_device *xe) if (!xe->info.has_i2c) return 0; - if (IS_SRIOV_VF(xe)) - return 0; - xe_i2c_read_endpoint(xe_root_tile_mmio(xe), &ep); if (ep.cookie != XE_I2C_EP_COOKIE_DEVICE) return 0; diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index a4292a11391d..3e7c995085d0 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -2618,13 +2618,19 @@ void xe_lrc_snapshot_free(struct xe_lrc_snapshot *snapshot) kfree(snapshot); } +static bool engine_valid_for_utilization(struct xe_gt *gt, struct xe_hw_engine *hwe) +{ + /* The USM-reserved copy engine runs kernel migrate contexts queried here */ + return hwe && (!xe_hw_engine_is_reserved(hwe) || xe_gt_is_usm_hwe(gt, hwe)); +} + static struct xe_hw_engine *engine_id_to_hwe(struct xe_gt *gt, u32 engine_id) { u16 class = REG_FIELD_GET(ENGINE_CLASS_ID, engine_id); u16 instance = REG_FIELD_GET(ENGINE_INSTANCE_ID, engine_id); struct xe_hw_engine *hwe = xe_gt_hw_engine(gt, class, instance, false); - if (xe_gt_WARN_ONCE(gt, !hwe || xe_hw_engine_is_reserved(hwe), + if (xe_gt_WARN_ONCE(gt, !engine_valid_for_utilization(gt, hwe), "Unexpected engine class:instance %d:%d for utilization\n", class, instance)) return NULL; diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 78adb303b663..7fa18dfcb5a2 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -11,27 +11,18 @@ #include #include -#include #include "regs/xe_bars.h" #include "xe_device.h" #include "xe_gt_sriov_vf.h" +#include "xe_printk.h" #include "xe_sriov.h" +#include "xe_tile_printk.h" #include "xe_trace.h" #include "xe_wa.h" #include "generated/xe_device_wa_oob.h" -static void tiles_fini(void *arg) -{ - struct xe_device *xe = arg; - struct xe_tile *tile; - int id; - - for_each_remote_tile(tile, xe, id) - tile->mmio.regs = NULL; -} - /* * On multi-tile devices, partition the BAR space for MMIO on each tile, * possibly accounting for register override on the number of tiles available. @@ -56,50 +47,71 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) struct xe_tile *tile; u8 id; + for_each_remote_tile(tile, xe, id) + xe_mmio_init(&tile->mmio, tile, xe->mmio.regs + id * tile_mmio_size, SZ_4M); +} + +/** + * xe_mmio_probe_tiles() - Initialize all tiles' MMIO + * @xe: the &xe_device + * + * Initialize the remaining tiles' MMIO instances. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_mmio_probe_tiles(struct xe_device *xe) +{ + size_t tile_mmio_size = SZ_16M; + /* * Nothing to be done as tile 0 has already been setup earlier with the * entire BAR mapped - see xe_mmio_probe_early() */ if (xe->info.tile_count == 1) - return; + return 0; - for_each_remote_tile(tile, xe, id) - xe_mmio_init(&tile->mmio, tile, xe->mmio.regs + id * tile_mmio_size, SZ_4M); -} - -int xe_mmio_probe_tiles(struct xe_device *xe) -{ - size_t tile_mmio_size = SZ_16M; + if (xe->mmio.size < xe->info.tile_count * tile_mmio_size) { + xe_err(xe, "GTTMMADR_BAR is too small for %d tiles: %zu\n", + xe->info.tile_count, xe->mmio.size); + return -EIO; + } mmio_multi_tile_setup(xe, tile_mmio_size); - - return devm_add_action_or_reset(xe->drm.dev, tiles_fini, xe); + return 0; } static void mmio_fini(void *arg) { struct xe_device *xe = arg; - struct xe_tile *root_tile = xe_device_get_root_tile(xe); - pci_iounmap(to_pci_dev(xe->drm.dev), xe->mmio.regs); xe->mmio.regs = NULL; - root_tile->mmio.regs = NULL; } +/** + * xe_mmio_probe_early() - Probe and initialize device's MMIO + * @xe: the &xe_device + * + * Map the entire GTTMMADR_BAR and initialize the first tile's MMIO instance. + * + * The first 16MB of the GTTMMADR_BAR always belongs to the root tile, and + * includes: registers (0-4MB), reserved space (4MB-8MB) and GGTT (8MB-16MB). + * + * Return: 0 on success or a negative error code on failure. + */ int xe_mmio_probe_early(struct xe_device *xe) { struct xe_tile *root_tile = xe_device_get_root_tile(xe); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); - /* - * Map the entire BAR. - * The first 16MB of the BAR, belong to the root tile, and include: - * registers (0-4MB), reserved space (4MB-8MB) and GGTT (8MB-16MB). - */ - xe->mmio.size = pci_resource_len(pdev, GTTMMADR_BAR); - xe->mmio.regs = pci_iomap(pdev, GTTMMADR_BAR, 0); + xe->mmio.regs = pcim_iomap(pdev, GTTMMADR_BAR, 0); if (!xe->mmio.regs) { - drm_err(&xe->drm, "failed to map registers\n"); + xe_err(xe, "Failed to map GTTMMADR_BAR\n"); + return -EIO; + } + + xe->mmio.size = pci_resource_len(pdev, GTTMMADR_BAR); + if (xe->mmio.size < SZ_16M) { + xe_err(xe, "GTTMMADR_BAR is too small: %zu\n", xe->mmio.size); return -EIO; } @@ -128,6 +140,11 @@ void xe_mmio_init(struct xe_mmio *mmio, struct xe_tile *tile, void __iomem *ptr, mmio->tile = tile; } +static bool mmio_available(struct xe_mmio *mmio) +{ + return !xe_tile_WARN_ON_ONCE(mmio->tile, !mmio->tile->xe->mmio.regs); +} + static void mmio_flush_pending_writes(struct xe_mmio *mmio) { #define DUMMY_REG_OFFSET 0x130030 @@ -146,6 +163,9 @@ u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg) u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u8 val; + if (!mmio_available(mmio)) + return 0; + mmio_flush_pending_writes(mmio); val = readb(mmio->regs + addr); @@ -158,6 +178,9 @@ void xe_mmio_write8(struct xe_mmio *mmio, struct xe_reg reg, u8 val) { u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); + if (!mmio_available(mmio)) + return; + trace_xe_reg_rw(mmio, true, addr, val, sizeof(val)); writeb(val, mmio->regs + addr); @@ -168,6 +191,9 @@ u16 xe_mmio_read16(struct xe_mmio *mmio, struct xe_reg reg) u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u16 val; + if (!mmio_available(mmio)) + return 0; + mmio_flush_pending_writes(mmio); val = readw(mmio->regs + addr); @@ -180,6 +206,9 @@ void xe_mmio_write32(struct xe_mmio *mmio, struct xe_reg reg, u32 val) { u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); + if (!mmio_available(mmio)) + return; + trace_xe_reg_rw(mmio, true, addr, val, sizeof(val)); if (!reg.vf && IS_SRIOV_VF(mmio->tile->xe)) @@ -194,6 +223,9 @@ u32 xe_mmio_read32(struct xe_mmio *mmio, struct xe_reg reg) u32 addr = xe_mmio_adjusted_addr(mmio, reg.addr); u32 val; + if (!mmio_available(mmio)) + return 0; + mmio_flush_pending_writes(mmio); if (!reg.vf && IS_SRIOV_VF(mmio->tile->xe)) @@ -282,8 +314,8 @@ u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg) oldudw = udw; } - drm_WARN(&mmio->tile->xe->drm, retries == 0, - "64-bit read of %#x did not stabilize\n", reg.addr); + xe_tile_WARN(mmio->tile, retries == 0, + "MMIO: 64-bit read of %#x did not stabilize\n", reg.addr); return (u64)udw << 32 | ldw; } diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c index 4cb578182912..39e4fc85f019 100644 --- a/drivers/gpu/drm/xe/xe_module.c +++ b/drivers/gpu/drm/xe/xe_module.c @@ -36,9 +36,6 @@ module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, uint, 0600) MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size in MiB, must be power of 2 " "[default=" __stringify(XE_DEFAULT_SVM_NOTIFIER_SIZE) "]"); -module_param_named_unsafe(force_execlist, xe_modparam.force_execlist, bool, 0444); -MODULE_PARM_DESC(force_execlist, "Force Execlist submission"); - #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY) module_param_named(probe_display, xe_modparam.probe_display, bool, 0444); MODULE_PARM_DESC(probe_display, "Probe display HW, otherwise it's left untouched " diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h index 79cb9639c0f3..c75153471248 100644 --- a/drivers/gpu/drm/xe/xe_module.h +++ b/drivers/gpu/drm/xe/xe_module.h @@ -10,7 +10,6 @@ /* Module modprobe variables */ struct xe_modparam { - bool force_execlist; bool probe_display; int force_vram_bar_size; int guc_log_level; diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 4bf4b1f65929..b3acbcd678b7 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -37,6 +37,7 @@ #include "xe_oa.h" #include "xe_observation.h" #include "xe_pm.h" +#include "xe_reg_whitelist.h" #include "xe_sched_job.h" #include "xe_sriov.h" #include "xe_sync.h" @@ -885,6 +886,9 @@ static void xe_oa_stream_destroy(struct xe_oa_stream *stream) mutex_destroy(&stream->stream_lock); + if (stream->sample) + xe_reg_dewhitelist_oa_regs(stream->gt); + xe_oa_disable_metric_set(stream); xe_exec_queue_put(stream->k_exec_q); @@ -1698,11 +1702,12 @@ static int xe_oa_release(struct inode *inode, struct file *file) static int xe_oa_mmap(struct file *file, struct vm_area_struct *vma) { struct xe_oa_stream *stream = file->private_data; + int ret = xe_observation_paranoid_check(); struct xe_bo *bo = stream->oa_buffer.bo; - if (xe_observation_paranoid && !perfmon_capable()) { + if (ret) { drm_dbg(&stream->oa->xe->drm, "Insufficient privilege to map OA buffer\n"); - return -EACCES; + return ret; } /* Can mmap the entire OA buffer or nothing (no partial OA buffer mmaps) */ @@ -1885,6 +1890,9 @@ static int xe_oa_stream_open_ioctl_locked(struct xe_oa *oa, goto err_disable; } + if (stream->sample) + xe_reg_whitelist_oa_regs(stream->gt); + /* Hold a reference on the drm device till stream_fd is released */ drm_dev_get(&stream->oa->xe->drm); @@ -2073,10 +2081,12 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f privileged_op = true; } - if (privileged_op && xe_observation_paranoid && !perfmon_capable()) { - drm_dbg(&oa->xe->drm, "Insufficient privileges to open xe OA stream\n"); - ret = -EACCES; - goto err_exec_q; + if (privileged_op) { + ret = xe_observation_paranoid_check(); + if (ret) { + drm_dbg(&oa->xe->drm, "Insufficient privileges to open xe OA stream\n"); + goto err_exec_q; + } } if (!param.exec_q && !param.sample) { @@ -2358,9 +2368,10 @@ int xe_oa_add_config_ioctl(struct drm_device *dev, u64 data, struct drm_file *fi return -ENODEV; } - if (xe_observation_paranoid && !perfmon_capable()) { + err = xe_observation_paranoid_check(); + if (err) { drm_dbg(&oa->xe->drm, "Insufficient privileges to add xe OA config\n"); - return -EACCES; + return err; } err = copy_from_user(¶m, u64_to_user_ptr(data), sizeof(param)); @@ -2460,9 +2471,10 @@ int xe_oa_remove_config_ioctl(struct drm_device *dev, u64 data, struct drm_file return -ENODEV; } - if (xe_observation_paranoid && !perfmon_capable()) { + ret = xe_observation_paranoid_check(); + if (ret) { drm_dbg(&oa->xe->drm, "Insufficient privileges to remove xe OA config\n"); - return -EACCES; + return ret; } ret = get_user(arg, ptr); diff --git a/drivers/gpu/drm/xe/xe_oa_types.h b/drivers/gpu/drm/xe/xe_oa_types.h index 3d9ec8490899..e876e9be92ba 100644 --- a/drivers/gpu/drm/xe/xe_oa_types.h +++ b/drivers/gpu/drm/xe/xe_oa_types.h @@ -126,6 +126,9 @@ struct xe_oa_gt { /** @oa_unit: array of oa_units */ struct xe_oa_unit *oa_unit; + + /** @whitelist_count: number of open streams for which oa registers are whitelisted */ + u32 whitelist_count; }; /** diff --git a/drivers/gpu/drm/xe/xe_observation.c b/drivers/gpu/drm/xe/xe_observation.c index e3f9b546207e..39e05b9131a7 100644 --- a/drivers/gpu/drm/xe/xe_observation.c +++ b/drivers/gpu/drm/xe/xe_observation.c @@ -4,6 +4,7 @@ */ #include +#include #include #include @@ -12,9 +13,28 @@ #include "xe_oa.h" #include "xe_observation.h" -u32 xe_observation_paranoid = true; +static u32 xe_observation_paranoid = true; static struct ctl_table_header *sysctl_header; +/** + * xe_observation_paranoid_check - Gate access to xe observation streams. + * + * When the xe-specific observation_paranoid sysctl is enabled (the + * default), defer to perf_allow_cpu() so that access is governed by the + * same policy as system-wide perf CPU events: kernel.perf_event_paranoid + * plus the security_perf_event_open() LSM hook. When the sysctl has been + * cleared by a privileged user, observation is open to all callers. + * + * Return: 0 if access is permitted, a negative errno otherwise. + */ +int xe_observation_paranoid_check(void) +{ + if (!xe_observation_paranoid) + return 0; + + return perf_allow_cpu(); +} + static int xe_oa_ioctl(struct drm_device *dev, struct drm_xe_observation_param *arg, struct drm_file *file) { @@ -83,11 +103,13 @@ static const struct ctl_table observation_ctl_table[] = { }; /** - * xe_observation_sysctl_register - Register xe_observation_paranoid sysctl + * xe_observation_sysctl_register - Register the observation_paranoid sysctl * - * Normally only superuser/root can access observation stream - * data. However, superuser can set xe_observation_paranoid sysctl to 0 to - * allow non-privileged users to also access observation data. + * When dev.xe.observation_paranoid is set (the default), access to + * observation streams follows the system-wide perf_allow_cpu() policy: + * kernel.perf_event_paranoid plus the security_perf_event_open() LSM + * hook. A privileged user can clear the sysctl to bypass that gate and + * allow unprivileged access to observation data. * * Return: always returns 0 */ diff --git a/drivers/gpu/drm/xe/xe_observation.h b/drivers/gpu/drm/xe/xe_observation.h index 17816998e966..73a03e03c96a 100644 --- a/drivers/gpu/drm/xe/xe_observation.h +++ b/drivers/gpu/drm/xe/xe_observation.h @@ -11,8 +11,7 @@ struct drm_device; struct drm_file; -extern u32 xe_observation_paranoid; - +int xe_observation_paranoid_check(void); int xe_observation_ioctl(struct drm_device *dev, void *data, struct drm_file *file); int xe_observation_sysctl_register(void); void xe_observation_sysctl_unregister(void); diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 3165686e3e04..91af603e9431 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -26,6 +26,7 @@ #include "xe_guc.h" #include "xe_mmio.h" #include "xe_module.h" +#include "xe_pci_error.h" #include "xe_pci_rebar.h" #include "xe_pci_sriov.h" #include "xe_pci_types.h" @@ -355,6 +356,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = { PLATFORM(PVC), .dma_mask_size = 52, .has_display = false, + .has_drm_ras = true, .has_gsc_nvm = 1, .has_heci_gscfi = 1, .max_gt_per_tile = 1, @@ -457,6 +459,7 @@ static const struct xe_device_desc cri_desc = { PLATFORM(CRESCENTISLAND), .dma_mask_size = 52, .has_display = false, + .has_drm_ras = true, .has_flat_ccs = false, .has_gsc_nvm = 1, .has_i2c = true, @@ -599,8 +602,6 @@ static int read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, u struct xe_reg gmdid_reg = GMD_ID; u32 val; - KUNIT_STATIC_STUB_REDIRECT(read_gmdid, xe, type, ver, revid); - if (IS_SRIOV_VF(xe)) { /* * To get the value of the GMDID register, VFs must obtain it @@ -726,14 +727,30 @@ static int handle_gmdid(struct xe_device *xe, return 0; } -static void init_devid(struct xe_device *xe) +struct xe_probed_info { + u16 devid; + u8 revid; + u8 tile_count; + struct xe_step_info step; + const struct xe_ip *graphics_ip; + const struct xe_ip *media_ip; +}; + +/* + * Probe from the hardware the info required by xe_info_init_early(). + */ +static int xe_probe_info_early(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) { struct pci_dev *pdev = to_pci_dev(xe->drm.dev); - KUNIT_STATIC_STUB_REDIRECT(init_devid, xe); + probed_info->devid = pdev->device; + probed_info->revid = pdev->revision; - xe->info.devid = pdev->device; - xe->info.revid = pdev->revision; + xe_step_platform_get(desc->platform, probed_info->revid, &probed_info->step); + + return 0; } /* @@ -742,17 +759,20 @@ static void init_devid(struct xe_device *xe) */ static int xe_info_init_early(struct xe_device *xe, const struct xe_device_desc *desc, - const struct xe_subplatform_desc *subplatform_desc) + const struct xe_subplatform_desc *subplatform_desc, + struct xe_probed_info *probed_info) { int err; + xe->info.devid = probed_info->devid; + xe->info.revid = probed_info->revid; + xe->info.step.platform = probed_info->step.platform; + xe->info.platform_name = desc->platform_name; xe->info.platform = desc->platform; xe->info.subplatform = subplatform_desc ? subplatform_desc->subplatform : XE_SUBPLATFORM_NONE; - init_devid(xe); - xe->info.dma_mask_size = desc->dma_mask_size; xe->info.va_bits = desc->va_bits; xe->info.vm_max_level = desc->vm_max_level; @@ -760,6 +780,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.is_dgfx = desc->is_dgfx; xe->info.has_cached_pt = desc->has_cached_pt; + xe->info.has_drm_ras = desc->has_drm_ras; xe->info.has_fan_control = desc->has_fan_control; /* runtime fusing may force flat_ccs to disabled later */ xe->info.has_flat_ccs = desc->has_flat_ccs; @@ -789,14 +810,10 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.probe_display = IS_ENABLED(CONFIG_DRM_XE_DISPLAY) && xe_modparam.probe_display && desc->has_display; - xe->info.force_execlist = xe_modparam.force_execlist; xe_assert(xe, desc->max_gt_per_tile > 0); xe_assert(xe, desc->max_gt_per_tile <= XE_MAX_GT_PER_TILE); xe->info.max_gt_per_tile = desc->max_gt_per_tile; - xe->info.tile_count = 1 + desc->max_remote_tiles; - - xe_step_platform_get(xe); err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0); if (err) @@ -805,22 +822,21 @@ static int xe_info_init_early(struct xe_device *xe, return 0; } -/* - * Possibly override number of tile based on configuration register. - */ -static void xe_info_probe_tile_count(struct xe_device *xe) +static void xe_probe_tile_count(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) { struct xe_mmio *mmio; u8 tile_count; u32 mtcfg; - KUNIT_STATIC_STUB_REDIRECT(xe_info_probe_tile_count, xe); + probed_info->tile_count = 1 + desc->max_remote_tiles; /* * Probe for tile count only for platforms that support multiple * tiles. */ - if (xe->info.tile_count == 1) + if (probed_info->tile_count == 1) return; mmio = xe_root_tile_mmio(xe); @@ -833,10 +849,10 @@ static void xe_info_probe_tile_count(struct xe_device *xe) mtcfg = xe_mmio_read32(mmio, XEHP_MTCFG_ADDR); tile_count = REG_FIELD_GET(TILE_COUNT, mtcfg) + 1; - if (tile_count < xe->info.tile_count) { + if (tile_count < probed_info->tile_count) { drm_info(&xe->drm, "tile_count: %d, reduced_tile_count %d\n", - xe->info.tile_count, tile_count); - xe->info.tile_count = tile_count; + probed_info->tile_count, tile_count); + probed_info->tile_count = tile_count; } } @@ -909,25 +925,10 @@ static struct xe_gt *alloc_media_gt(struct xe_tile *tile, return gt; } -/* - * Initialize device info content that does require knowledge about - * graphics / media IP version. - * Make sure that GT / tile structures allocated by the driver match the data - * present in device info. - */ -static int xe_info_init(struct xe_device *xe, - const struct xe_device_desc *desc) +static int xe_probe_ips(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) { - u32 graphics_gmdid_revid = 0, media_gmdid_revid = 0; - const struct xe_ip *graphics_ip; - const struct xe_ip *media_ip; - const struct xe_graphics_desc *graphics_desc; - const struct xe_media_desc *media_desc; - struct xe_tile *tile; - struct xe_gt *gt; - int ret; - u8 id; - /* * If this platform supports GMD_ID, we'll detect the proper IP * descriptor to use from hardware registers. @@ -936,17 +937,21 @@ static int xe_info_init(struct xe_device *xe, * versions are simply derived from that. */ if (desc->pre_gmdid_graphics_ip) { - graphics_ip = desc->pre_gmdid_graphics_ip; - media_ip = desc->pre_gmdid_media_ip; - xe_step_pre_gmdid_get(xe); + probed_info->graphics_ip = desc->pre_gmdid_graphics_ip; + probed_info->media_ip = desc->pre_gmdid_media_ip; + xe_step_pre_gmdid_get(xe, &probed_info->step); } else { - xe_assert(xe, !desc->pre_gmdid_media_ip); - ret = handle_gmdid(xe, &graphics_ip, &media_ip, - &graphics_gmdid_revid, &media_gmdid_revid); - if (ret) - return ret; + int err; + u32 graphics_revid, media_revid; - xe_step_gmdid_get(xe, graphics_gmdid_revid, media_gmdid_revid); + xe_assert(xe, !desc->pre_gmdid_media_ip); + + err = handle_gmdid(xe, &probed_info->graphics_ip, &probed_info->media_ip, + &graphics_revid, &media_revid); + if (err) + return err; + + xe_step_gmdid_get(xe, graphics_revid, media_revid, &probed_info->step); } /* @@ -954,9 +959,56 @@ static int xe_info_init(struct xe_device *xe, * error and we should abort driver load. Failing to detect media * IP is non-fatal; we'll just proceed without enabling media support. */ - if (!graphics_ip) + if (!probed_info->graphics_ip) return -ENODEV; + return 0; +} + +/* + * Probe from the hardware the info required by xe_info_init(). + */ +static int xe_probe_info(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) +{ + int err; + + xe_probe_tile_count(xe, desc, probed_info); + + err = xe_probe_ips(xe, desc, probed_info); + if (err) + return err; + + return 0; +} + +/* + * Initialize device info content that does require knowledge about + * graphics / media IP version. + * Make sure that GT / tile structures allocated by the driver match the data + * present in device info. + */ +static int xe_info_init(struct xe_device *xe, + const struct xe_device_desc *desc, + struct xe_probed_info *probed_info) +{ + const struct xe_ip *graphics_ip; + const struct xe_ip *media_ip; + const struct xe_graphics_desc *graphics_desc; + const struct xe_media_desc *media_desc; + struct xe_tile *tile; + struct xe_gt *gt; + u8 id; + + graphics_ip = probed_info->graphics_ip; + media_ip = probed_info->media_ip; + + xe->info.tile_count = probed_info->tile_count; + xe->info.step.basedie = probed_info->step.basedie; + xe->info.step.graphics = probed_info->step.graphics; + xe->info.step.media = probed_info->step.media; + xe->info.graphics_verx100 = graphics_ip->verx100; xe->info.graphics_name = graphics_ip->name; graphics_desc = graphics_ip->desc; @@ -988,8 +1040,6 @@ static int xe_info_init(struct xe_device *xe, xe->info.has_soc_remapper_telem = 0; } - xe_info_probe_tile_count(xe); - for_each_remote_tile(tile, xe, id) { int err; @@ -1072,9 +1122,11 @@ static void xe_pci_remove(struct pci_dev *pdev) */ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { + struct xe_probed_info probed_info = {}; const struct xe_device_desc *desc = (const void *)ent->driver_data; const struct xe_subplatform_desc *subplatform_desc; struct xe_device *xe; + void *group; int err; subplatform_desc = find_subplatform(desc, pdev->device); @@ -1102,6 +1154,11 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (xe_display_driver_probe_defer(pdev)) return -EPROBE_DEFER; + /* Group all devres so xe_pci_error_slot_reset() can release them as a unit. */ + group = devres_open_group(&pdev->dev, NULL, GFP_KERNEL); + if (!group) + return -ENOMEM; + err = pcim_enable_device(pdev); if (err) return err; @@ -1110,13 +1167,19 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (IS_ERR(xe)) return PTR_ERR(xe); + xe->devres_group = group; + pci_set_drvdata(pdev, &xe->drm); xe_pm_assert_unbounded_bridge(xe); pci_set_master(pdev); - err = xe_info_init_early(xe, desc, subplatform_desc); + err = xe_probe_info_early(xe, desc, &probed_info); + if (err) + return err; + + err = xe_info_init_early(xe, desc, subplatform_desc, &probed_info); if (err) return err; @@ -1135,7 +1198,11 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) return err; - err = xe_info_init(xe, desc); + err = xe_probe_info(xe, desc, &probed_info); + if (err) + return err; + + err = xe_info_init(xe, desc, &probed_info); if (err) return err; @@ -1348,6 +1415,7 @@ static struct pci_driver xe_pci_driver = { .remove = xe_pci_remove, .shutdown = xe_pci_shutdown, .sriov_configure = xe_pci_sriov_configure, + .err_handler = &xe_pci_error_handlers, #ifdef CONFIG_PM_SLEEP .driver.pm = &xe_pm_ops, #endif diff --git a/drivers/gpu/drm/xe/xe_pci_error.c b/drivers/gpu/drm/xe/xe_pci_error.c new file mode 100644 index 000000000000..9b78cc0d3293 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pci_error.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include + +#include "xe_device.h" +#include "xe_gt.h" +#include "xe_pci.h" +#include "xe_pm.h" +#include "xe_printk.h" +#include "xe_survivability_mode.h" + +static void prepare_device_for_reset(struct pci_dev *pdev) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + struct xe_gt *gt; + u8 id; + + /* + * Wedge the device to prevent userspace access but do not send the uevent. + * xe_device_wedged_fini() releases runtime pm if wedged flag is set, so acquire a runtime + * pm reference to avoid underflow. + */ + if (!atomic_xchg(&xe->wedged.flag, 1)) + xe_pm_runtime_get_noresume(xe); + + xe_device_set_in_reset(xe); + + for_each_gt(gt, xe, id) + xe_gt_declare_wedged(gt); + + pci_disable_device(pdev); +} + +static pci_ers_result_t xe_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: detected state = %d\n", state); + + if (state == pci_channel_io_perm_failure) + return PCI_ERS_RESULT_DISCONNECT; + + /* If the device is already wedged or in survivability mode, do not attempt recovery */ + if (xe_survivability_mode_is_boot_enabled(xe) || xe_device_wedged(xe)) + return PCI_ERS_RESULT_DISCONNECT; + + switch (state) { + case pci_channel_io_normal: + return PCI_ERS_RESULT_CAN_RECOVER; + case pci_channel_io_frozen: + prepare_device_for_reset(pdev); + return PCI_ERS_RESULT_NEED_RESET; + default: + xe_info(xe, "PCI error: unknown state %d\n", state); + return PCI_ERS_RESULT_DISCONNECT; + } +} + +static pci_ers_result_t xe_pci_error_mmio_enabled(struct pci_dev *pdev) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: MMIO enabled\n"); + + /* TODO: Query system controller for the type of error and take appropriate action */ + return PCI_ERS_RESULT_RECOVERED; +} + +static pci_ers_result_t xe_pci_error_slot_reset(struct pci_dev *pdev) +{ + const struct pci_device_id *ent = pci_match_id(pdev->driver->id_table, pdev); + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: slot reset\n"); + + pci_restore_state(pdev); + + if (pci_enable_device(pdev)) { + xe_err(xe, "Cannot re-enable PCI device after reset\n"); + return PCI_ERS_RESULT_DISCONNECT; + } + + /* + * Secondary Bus Reset causes all VRAM state to be lost along with + * hardware state. As an initial step, re-probe the device to + * re-initialize the driver and hardware. + * TODO: optimize by re-initializing only the hardware state and re-creating + * kernel BOs. + */ + xe_device_clear_in_reset(xe); + pdev->driver->remove(pdev); + devres_release_group(&pdev->dev, xe->devres_group); + + if (pdev->driver->probe(pdev, ent)) + return PCI_ERS_RESULT_DISCONNECT; + + xe = pdev_to_xe_device(pdev); + + /* Wedge the device to prevent I/O operations till the resume callback */ + atomic_set(&xe->wedged.flag, 1); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void xe_pci_error_resume(struct pci_dev *pdev) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + + xe_info(xe, "PCI error: resume\n"); + + atomic_set(&xe->wedged.flag, 0); +} + +const struct pci_error_handlers xe_pci_error_handlers = { + .error_detected = xe_pci_error_detected, + .mmio_enabled = xe_pci_error_mmio_enabled, + .slot_reset = xe_pci_error_slot_reset, + .resume = xe_pci_error_resume, +}; diff --git a/drivers/gpu/drm/xe/xe_pci_error.h b/drivers/gpu/drm/xe/xe_pci_error.h new file mode 100644 index 000000000000..725ad0214e62 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pci_error.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_PCI_ERROR_H_ +#define _XE_PCI_ERROR_H_ + +struct pci_error_handlers; + +extern const struct pci_error_handlers xe_pci_error_handlers; + +#endif diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 5b85e2c24b7b..24d4a3d00517 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -40,6 +40,7 @@ struct xe_device_desc { u8 has_cached_pt:1; u8 has_display:1; + u8 has_drm_ras:1; u8 has_fan_control:1; u8 has_flat_ccs:1; u8 has_gsc_nvm:1; diff --git a/drivers/gpu/drm/xe/xe_pcode.c b/drivers/gpu/drm/xe/xe_pcode.c index dc66d0c7ee06..866986694d9c 100644 --- a/drivers/gpu/drm/xe/xe_pcode.c +++ b/drivers/gpu/drm/xe/xe_pcode.c @@ -323,15 +323,17 @@ int xe_pcode_ready(struct xe_device *xe, bool locked) } /** - * xe_pcode_init: initialize components of PCODE + * xe_pcode_init_early() - Initialize components of PCODE * @tile: tile instance * * This function initializes the xe_pcode component. * To be called once only during probe. + * + * Return: 0 on success or a negative error code on failure. */ -void xe_pcode_init(struct xe_tile *tile) +int xe_pcode_init_early(struct xe_tile *tile) { - drmm_mutex_init(&tile_to_xe(tile)->drm, &tile->pcode.lock); + return drmm_mutex_init(&tile_to_xe(tile)->drm, &tile->pcode.lock); } /** diff --git a/drivers/gpu/drm/xe/xe_pcode.h b/drivers/gpu/drm/xe/xe_pcode.h index 490e4f269607..18260c29e620 100644 --- a/drivers/gpu/drm/xe/xe_pcode.h +++ b/drivers/gpu/drm/xe/xe_pcode.h @@ -12,7 +12,7 @@ struct drm_device; struct xe_device; struct xe_tile; -void xe_pcode_init(struct xe_tile *tile); +int xe_pcode_init_early(struct xe_tile *tile); int xe_pcode_probe_early(struct xe_device *xe); int xe_pcode_ready(struct xe_device *xe, bool locked); int xe_pcode_init_min_freq_table(struct xe_tile *tile, u32 min_gt_freq, diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 18a98667c0e6..5fdad444009f 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -433,6 +433,7 @@ xe_pt_insert_entry(struct xe_pt_stage_bind_walk *xe_walk, struct xe_pt *parent, static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level, struct xe_pt_stage_bind_walk *xe_walk) { + struct xe_bo *bo = xe_vma_bo(xe_walk->vma); u64 size, dma; if (level > MAX_HUGEPTE_LEVEL) @@ -446,8 +447,8 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level, if (next - xe_walk->va_curs_start > xe_walk->curs->size) return false; - /* null VMA's do not have dma addresses */ - if (xe_vma_is_null(xe_walk->vma)) + /* null VMA's and purged BO's do not have dma addresses */ + if (xe_vma_is_null(xe_walk->vma) || (bo && xe_bo_is_purged(bo))) return true; /* if we are clearing page table, no dma addresses*/ @@ -468,6 +469,7 @@ static bool xe_pt_hugepte_possible(u64 addr, u64 next, unsigned int level, static bool xe_pt_scan_64K(u64 addr, u64 next, struct xe_pt_stage_bind_walk *xe_walk) { + struct xe_bo *bo = xe_vma_bo(xe_walk->vma); struct xe_res_cursor curs = *xe_walk->curs; if (!IS_ALIGNED(addr, SZ_64K)) @@ -476,8 +478,8 @@ xe_pt_scan_64K(u64 addr, u64 next, struct xe_pt_stage_bind_walk *xe_walk) if (next > xe_walk->l0_end_addr) return false; - /* null VMA's do not have dma addresses */ - if (xe_vma_is_null(xe_walk->vma)) + /* null VMA's and purged BO's do not have dma addresses */ + if (xe_vma_is_null(xe_walk->vma) || (bo && xe_bo_is_purged(bo))) return true; xe_res_next(&curs, addr - xe_walk->va_curs_start); @@ -708,7 +710,7 @@ xe_pt_stage_bind(struct xe_tile *tile, struct xe_vma *vma, { struct xe_device *xe = tile_to_xe(tile); struct xe_bo *bo = xe_vma_bo(vma); - struct xe_res_cursor curs; + struct xe_res_cursor curs = {}; struct xe_vm *vm = xe_vma_vm(vma); struct xe_pt_stage_bind_walk xe_walk = { .base = { @@ -885,12 +887,20 @@ static int xe_pt_zap_ptes_entry(struct xe_ptw *parent, pgoff_t offset, { struct xe_pt_zap_ptes_walk *xe_walk = container_of(walk, typeof(*xe_walk), base); - struct xe_pt *xe_child = container_of(*child, typeof(*xe_child), base); + struct xe_pt *xe_child; pgoff_t end_offset; - XE_WARN_ON(!*child); XE_WARN_ON(!level); + /* + * Below would be unexpected behavior that needs to be root caused + * but better warn and bail than crash the driver. + */ + if (XE_WARN_ON(!*child)) + return 0; + + xe_child = container_of(*child, typeof(*xe_child), base); + /* * Note that we're called from an entry callback, and we're dealing * with the child of that entry rather than the parent, so need to @@ -1016,12 +1026,22 @@ xe_vm_populate_pgtable(struct xe_migrate_pt_update *pt_update, struct xe_tile *t u64 *ptr = data; u32 i; + /* + * @qword_ofs is the absolute entry offset within the page table, while + * @ptes is indexed relative to @update->ofs (its first entry). The GPU + * path (write_pgtable) splits a single update into MAX_PTE_PER_SDI-sized + * chunks, calling this with an advancing @qword_ofs but a fresh @data + * pointer per chunk, so translate back into a @ptes index rather than + * assuming the chunk starts at ptes[0]. + */ for (i = 0; i < num_qwords; i++) { + u32 idx = qword_ofs - update->ofs + i; + if (map) xe_map_wr(tile_to_xe(tile), map, (qword_ofs + i) * - sizeof(u64), u64, ptes[i].pte); + sizeof(u64), u64, ptes[idx].pte); else - ptr[i] = ptes[i].pte; + ptr[i] = ptes[idx].pte; } } @@ -1078,7 +1098,7 @@ static void xe_pt_commit_locks_assert(struct xe_vma *vma) xe_pt_commit_prepare_locks_assert(vma); if (xe_vma_is_userptr(vma)) - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); } static void xe_pt_commit(struct xe_vma *vma, @@ -1398,6 +1418,33 @@ static int xe_pt_pre_commit(struct xe_migrate_pt_update *pt_update) pt_update_ops, rftree); } +/* + * Acquire/release the svm notifier_lock around xe_pt_svm_userptr_pre_commit() + * and the matching late release in xe_pt_update_ops_run(). Read mode by + * default; write mode when CONFIG_DRM_XE_USERPTR_INVAL_INJECT is on, + * because a userptr op in this critical section may invoke the injected + * xe_vma_userptr_force_invalidate() path that calls + * drm_gpusvm_unmap_pages() with ctx->in_notifier=true, which requires the + * lock held for write. + */ +static void xe_pt_svm_userptr_notifier_lock(struct xe_vm *vm) +{ +#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) + down_write(&vm->svm.gpusvm.notifier_lock); +#else + xe_svm_notifier_lock(vm); +#endif +} + +static void xe_pt_svm_userptr_notifier_unlock(struct xe_vm *vm) +{ +#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) + up_write(&vm->svm.gpusvm.notifier_lock); +#else + xe_svm_notifier_unlock(vm); +#endif +} + #if IS_ENABLED(CONFIG_DRM_GPUSVM) #ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT @@ -1429,7 +1476,7 @@ static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma, struct xe_userptr_vma *uvma; unsigned long notifier_seq; - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); if (!xe_vma_is_userptr(vma)) return 0; @@ -1459,7 +1506,7 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op, { int err = 0; - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); switch (op->base.op) { case DRM_GPUVA_OP_MAP: @@ -1531,12 +1578,12 @@ static int xe_pt_svm_userptr_pre_commit(struct xe_migrate_pt_update *pt_update) if (err) return err; - xe_svm_notifier_lock(vm); + xe_pt_svm_userptr_notifier_lock(vm); list_for_each_entry(op, &vops->list, link) { err = op_check_svm_userptr(vm, op, pt_update_ops); if (err) { - xe_svm_notifier_unlock(vm); + xe_pt_svm_userptr_notifier_unlock(vm); break; } } @@ -2033,6 +2080,9 @@ static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile, * automatically when the context is re-enabled by the rebind worker, * or in fault mode it was invalidated on PTE zapping. * + * If rebind, we have to invalidate TLB on context based TLB invalidation + * LR vms, as they cannot be relied on context re-enable. + * * If !rebind, and scratch enabled VMs, there is a chance the scratch * PTE is already cached in the TLB so it needs to be invalidated. * On !LR VMs this is done in the ring ops preceding a batch, but on @@ -2042,6 +2092,9 @@ static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile, if ((!pt_op->rebind && xe_vm_has_scratch(vm) && xe_vm_in_lr_mode(vm))) pt_update_ops->needs_invalidation = true; + else if (pt_op->rebind && xe_vm_in_preempt_fence_mode(vm) && + vm->xe->info.has_ctx_tlb_inval) + pt_update_ops->needs_invalidation = true; else if (pt_op->rebind && !xe_vm_in_lr_mode(vm)) /* We bump also if batch_invalidate_tlb is true */ vm->tlb_flush_seqno++; @@ -2395,7 +2448,7 @@ static void bind_op_commit(struct xe_vm *vm, struct xe_tile *tile, vma->tile_invalidated & ~BIT(tile->id)); vma->tile_staged &= ~BIT(tile->id); if (xe_vma_is_userptr(vma)) { - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); to_userptr_vma(vma)->userptr.initial_bind = true; } @@ -2431,7 +2484,7 @@ static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile, if (!vma->tile_present) { list_del_init(&vma->combined_links.rebind); if (xe_vma_is_userptr(vma)) { - xe_svm_assert_held_read(vm); + xe_svm_assert_held_read_or_inject_write(vm); spin_lock(&vm->userptr.invalidated_lock); list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link); @@ -2707,7 +2760,7 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops) } if (pt_update_ops->needs_svm_lock) - xe_svm_notifier_unlock(vm); + xe_pt_svm_userptr_notifier_unlock(vm); /* * The last fence is only used for zero bind queue idling; migrate diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 968b7e70b3f9..fea3d8ceeddb 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -59,6 +59,7 @@ bool xe_pxp_is_enabled(const struct xe_pxp *pxp) static bool pxp_prerequisites_done(const struct xe_pxp *pxp) { struct xe_gt *gt = pxp->gt; + bool huc_ok; bool ready; CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); @@ -73,9 +74,14 @@ static bool pxp_prerequisites_done(const struct xe_pxp *pxp) */ XE_WARN_ON(!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)); - /* PXP requires both HuC authentication via GSC and GSC proxy initialized */ - ready = xe_huc_is_authenticated(>->uc.huc, XE_HUC_AUTH_VIA_GSC) && - xe_gsc_proxy_init_done(>->uc.gsc); + /* + * PXP requires GSC proxy to be initialized. On platforms where the HuC + * is loaded by the kernel driver (i.e., pre media 35) PXP also requires + * the HuC to be authenticated by GSC. + */ + huc_ok = MEDIA_VER(gt_to_xe(gt)) >= 35 || + xe_huc_is_authenticated(>->uc.huc, XE_HUC_AUTH_VIA_GSC); + ready = huc_ok && xe_gsc_proxy_init_done(>->uc.gsc); return ready; } @@ -97,9 +103,13 @@ int xe_pxp_get_readiness_status(struct xe_pxp *pxp) if (!xe_pxp_is_enabled(pxp)) return -ENODEV; - /* if the GSC or HuC FW are in an error state, PXP will never work */ - if (xe_uc_fw_status_to_error(pxp->gt->uc.huc.fw.status) || - xe_uc_fw_status_to_error(pxp->gt->uc.gsc.fw.status)) + /* If the GSC FW is in an error state, PXP will never work */ + if (xe_uc_fw_status_to_error(pxp->gt->uc.gsc.fw.status)) + return -EIO; + + /* Same for HuC FW, but only if the kernel owns HuC-loading (i.e. pre-NVL) */ + if (MEDIA_VER(gt_to_xe(pxp->gt)) < 35 && + xe_uc_fw_status_to_error(pxp->gt->uc.huc.fw.status)) return -EIO; guard(xe_pm_runtime)(pxp->xe); @@ -361,6 +371,7 @@ static void pxp_fini(void *arg) int xe_pxp_init(struct xe_device *xe) { struct xe_gt *gt = xe->tiles[0].media_gt; + bool gsc_ok, huc_ok; struct xe_pxp *pxp; int err; @@ -375,10 +386,14 @@ int xe_pxp_init(struct xe_device *xe) if (!(gt->info.engine_mask & BIT(XE_HW_ENGINE_GSCCS0))) return 0; - /* PXP requires both GSC and HuC firmwares to be available */ - if (!xe_uc_fw_is_loadable(>->uc.gsc.fw) || - !xe_uc_fw_is_loadable(>->uc.huc.fw)) { - drm_info(&xe->drm, "skipping PXP init due to missing FW dependencies"); + /* PXP requires GSC FW to be available. Pre-NVL it also requires HuC FW */ + gsc_ok = xe_uc_fw_is_loadable(>->uc.gsc.fw); + huc_ok = MEDIA_VER(xe) >= 35 || xe_uc_fw_is_loadable(>->uc.huc.fw); + + if (!gsc_ok || !huc_ok) { + drm_info(&xe->drm, "Skipping PXP due to unsatisfied FW deps - GSC=%s, HuC=%s\n", + str_yes_no(gsc_ok), + MEDIA_VER(xe) >= 35 ? "not needed" : str_yes_no(huc_ok)); return 0; } diff --git a/drivers/gpu/drm/xe/xe_query.c b/drivers/gpu/drm/xe/xe_query.c index 8c7d54498f38..dc975f595368 100644 --- a/drivers/gpu/drm/xe/xe_query.c +++ b/drivers/gpu/drm/xe/xe_query.c @@ -119,6 +119,7 @@ query_engine_cycles(struct xe_device *xe, struct drm_xe_engine_class_instance *eci; struct drm_xe_query_engine_cycles resp; size_t size = sizeof(resp); + enum xe_force_wake_domains fw_domain; __ktime_func_t cpu_clock; struct xe_hw_engine *hwe; struct xe_gt *gt; @@ -154,8 +155,10 @@ query_engine_cycles(struct xe_device *xe, if (!hwe) return -EINVAL; - xe_with_force_wake(fw_ref, gt_to_fw(gt), XE_FORCEWAKE_ALL) { - if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) + fw_domain = xe_hw_engine_to_fw_domain(hwe); + + xe_with_force_wake(fw_ref, gt_to_fw(gt), fw_domain) { + if (!xe_force_wake_ref_has_domain(fw_ref.domains, fw_domain)) return -EIO; hwe_read_timestamp(hwe, &resp.engine_cycles, &resp.cpu_timestamp, diff --git a/drivers/gpu/drm/xe/xe_ras.c b/drivers/gpu/drm/xe/xe_ras.c index 4cb16b419b0c..74d5016d9ffe 100644 --- a/drivers/gpu/drm/xe/xe_ras.c +++ b/drivers/gpu/drm/xe/xe_ras.c @@ -4,11 +4,15 @@ */ #include "xe_device.h" +#include "xe_drm_ras.h" +#include "xe_pm.h" #include "xe_printk.h" #include "xe_ras.h" #include "xe_ras_types.h" #include "xe_sysctrl.h" #include "xe_sysctrl_event_types.h" +#include "xe_sysctrl_mailbox.h" +#include "xe_sysctrl_mailbox_types.h" /* Severity of detected errors */ enum xe_ras_severity { @@ -31,6 +35,17 @@ enum xe_ras_component { XE_RAS_COMP_MAX }; +/* RAS response status codes */ +enum xe_ras_response_status { + XE_RAS_STATUS_SUCCESS = 0, + XE_RAS_STATUS_INVALID_PARAM, + XE_RAS_STATUS_OP_NOT_SUPPORTED, + XE_RAS_STATUS_TIMEOUT, + XE_RAS_STATUS_HARDWARE_FAILURE, + XE_RAS_STATUS_INSUFFICIENT_RESOURCES, + XE_RAS_STATUS_MAX +}; + static const char *const xe_ras_severities[] = { [XE_RAS_SEV_NOT_SUPPORTED] = "Not Supported", [XE_RAS_SEV_CORRECTABLE] = "Correctable Error", @@ -50,6 +65,56 @@ static const char *const xe_ras_components[] = { }; static_assert(ARRAY_SIZE(xe_ras_components) == XE_RAS_COMP_MAX); +static u8 drm_to_xe_ras_severity(u8 severity) +{ + switch (severity) { + case DRM_XE_RAS_ERR_SEV_CORRECTABLE: + return XE_RAS_SEV_CORRECTABLE; + case DRM_XE_RAS_ERR_SEV_UNCORRECTABLE: + return XE_RAS_SEV_UNCORRECTABLE; + default: + return XE_RAS_SEV_NOT_SUPPORTED; + } +} + +static u8 drm_to_xe_ras_component(u8 component) +{ + switch (component) { + case DRM_XE_RAS_ERR_COMP_CORE_COMPUTE: + return XE_RAS_COMP_CORE_COMPUTE; + case DRM_XE_RAS_ERR_COMP_SOC_INTERNAL: + return XE_RAS_COMP_SOC_INTERNAL; + case DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY: + return XE_RAS_COMP_DEVICE_MEMORY; + case DRM_XE_RAS_ERR_COMP_PCIE: + return XE_RAS_COMP_PCIE; + case DRM_XE_RAS_ERR_COMP_FABRIC: + return XE_RAS_COMP_FABRIC; + default: + return XE_RAS_COMP_NOT_SUPPORTED; + } +} + +static int ras_status_to_errno(u32 status) +{ + switch (status) { + case XE_RAS_STATUS_SUCCESS: + return 0; + case XE_RAS_STATUS_INVALID_PARAM: + return -EINVAL; + case XE_RAS_STATUS_OP_NOT_SUPPORTED: + return -EOPNOTSUPP; + case XE_RAS_STATUS_TIMEOUT: + return -ETIMEDOUT; + case XE_RAS_STATUS_HARDWARE_FAILURE: + return -EIO; + case XE_RAS_STATUS_INSUFFICIENT_RESOURCES: + return -ENOSPC; + default: + return -EPROTO; + } +} + static inline const char *sev_to_str(u8 severity) { if (severity >= XE_RAS_SEV_MAX) @@ -66,6 +131,68 @@ static inline const char *comp_to_str(u8 component) return xe_ras_components[component]; } +static struct pci_dev *find_usp_dev(struct pci_dev *pdev) +{ + struct pci_dev *vsp; + + /* + * Device Hierarchy: + * + * Upstream Switch Port (USP) --> Virtual Switch Port (VSP) --> SGunit (GPU endpoint) + */ + vsp = pci_upstream_bridge(pdev); + if (!vsp) + return NULL; + + return pci_upstream_bridge(vsp); +} + +static void ras_usp_aer_init(struct xe_device *xe) +{ + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + struct pci_dev *usp; + u16 aer_cap; + u32 status; + + usp = find_usp_dev(pdev); + if (!usp) + return; + + aer_cap = pci_find_ext_capability(usp, PCI_EXT_CAP_ID_ERR); + if (!aer_cap) { + dev_warn(&usp->dev, "AER capability unavailable\n"); + return; + } + + /* + * Clear any stale Uncorrectable Internal Error Status event in Uncorrectable Error + * Status Register. + */ + pci_read_config_dword(usp, aer_cap + PCI_ERR_UNCOR_STATUS, &status); + if (status & PCI_ERR_UNC_INTN) + pci_write_config_dword(usp, aer_cap + PCI_ERR_UNCOR_STATUS, PCI_ERR_UNC_INTN); + + /* + * All errors are steered to USP which is a PCIe AER Compliant device. + * Downgrade all the errors to non-fatal to prevent PCIe bus driver + * from triggering a Secondary Bus Reset (SBR). This allows error + * detection, containment and recovery in the driver. + * + * The Uncorrectable Error Severity Register has the 'Uncorrectable + * Internal Error Severity' set to fatal by default. Set this to + * non-fatal and unmask the error. + */ + + /* Downgrade Uncorrectable Internal Error to non-fatal */ + pci_clear_and_set_config_dword(usp, aer_cap + PCI_ERR_UNCOR_SEVER, PCI_ERR_UNC_INTN, 0); + + /* Unmask Uncorrectable Internal Error */ + pci_clear_and_set_config_dword(usp, aer_cap + PCI_ERR_UNCOR_MASK, PCI_ERR_UNC_INTN, 0); + + pci_save_state(usp); + dev_dbg(&usp->dev, "Uncorrectable Internal Errors downgraded and unmasked\n"); +} + void xe_ras_counter_threshold_crossed(struct xe_device *xe, struct xe_sysctrl_event_response *response) { @@ -91,3 +218,136 @@ void xe_ras_counter_threshold_crossed(struct xe_device *xe, comp_to_str(component), sev_to_str(severity)); } } + +static int get_counter(struct xe_device *xe, struct xe_ras_error_class *counter, u32 *value) +{ + struct xe_ras_get_counter_response response = {0}; + struct xe_ras_get_counter_request request = {0}; + struct xe_sysctrl_mailbox_command command = {0}; + struct xe_ras_error_common *common; + size_t rlen; + int ret; + + request.counter = *counter; + + xe_sysctrl_create_command(&command, XE_SYSCTRL_GROUP_GFSP, XE_SYSCTRL_CMD_GET_COUNTER, + &request, sizeof(request), &response, sizeof(response)); + + ret = xe_sysctrl_send_command(&xe->sc, &command, &rlen); + if (ret) { + xe_err(xe, "sysctrl: failed to get counter %d\n", ret); + return ret; + } + + if (rlen != sizeof(response)) { + xe_err(xe, "sysctrl: unexpected get counter response length %zu (expected %zu)\n", + rlen, sizeof(response)); + return -EIO; + } + + common = &response.counter.common; + *value = response.value; + + xe_dbg(xe, "[RAS]: get counter %u for %s %s\n", *value, comp_to_str(common->component), + sev_to_str(common->severity)); + + return 0; +} + +/** + * xe_ras_get_counter() - Get error counter value + * @xe: Xe device instance + * @severity: Error severity to be queried (&enum drm_xe_ras_error_severity) + * @component: Error component to be queried (&enum drm_xe_ras_error_component) + * @value: Counter value + * + * This function retrieves the value of a specific error counter based on + * the error severity and component. + * + * Return: 0 on success, negative error code on failure. + */ +int xe_ras_get_counter(struct xe_device *xe, u8 severity, u8 component, u32 *value) +{ + struct xe_ras_error_class counter = {0}; + + counter.common.severity = drm_to_xe_ras_severity(severity); + counter.common.component = drm_to_xe_ras_component(component); + + guard(xe_pm_runtime)(xe); + return get_counter(xe, &counter, value); +} + +/** + * xe_ras_clear_counter() - Clear error counter value + * @xe: Xe device instance + * @severity: Error severity to be cleared (&enum drm_xe_ras_error_severity) + * @component: Error component to be cleared (&enum drm_xe_ras_error_component) + * + * This function clears the value of a specific error counter based on + * the error severity and component. + * + * Return: 0 on success, negative error code on failure. + */ +int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component) +{ + struct xe_ras_clear_counter_response response = {0}; + struct xe_ras_clear_counter_request request = {0}; + struct xe_sysctrl_mailbox_command command = {0}; + struct xe_ras_error_class *counter; + size_t rlen; + int ret; + + counter = &request.counter; + counter->common.severity = drm_to_xe_ras_severity(severity); + counter->common.component = drm_to_xe_ras_component(component); + + xe_sysctrl_create_command(&command, XE_SYSCTRL_GROUP_GFSP, XE_SYSCTRL_CMD_CLEAR_COUNTER, + &request, sizeof(request), &response, sizeof(response)); + + guard(xe_pm_runtime)(xe); + ret = xe_sysctrl_send_command(&xe->sc, &command, &rlen); + if (ret) { + xe_err(xe, "sysctrl: failed to clear counter %d\n", ret); + return ret; + } + + if (rlen != sizeof(response)) { + xe_err(xe, "sysctrl: unexpected clear counter response length %zu (expected %zu)\n", + rlen, sizeof(response)); + return -EIO; + } + + ret = ras_status_to_errno(response.status); + if (ret) { + xe_err(xe, "sysctrl: clear counter command failed with status %#x\n", + response.status); + return ret; + } + + counter = &response.counter; + + xe_dbg(xe, "[RAS]: clear counter for %s %s\n", comp_to_str(counter->common.component), + sev_to_str(counter->common.severity)); + + return 0; +} + +/** + * xe_ras_init - Initialize Xe RAS + * @xe: xe device instance + * + * Initialize Xe RAS + */ +void xe_ras_init(struct xe_device *xe) +{ + if (!xe->info.has_drm_ras) + return; + + xe_drm_ras_init(xe); + + if (!xe->info.has_sysctrl) + return; + + if (IS_ENABLED(CONFIG_PCIEAER)) + ras_usp_aer_init(xe); +} diff --git a/drivers/gpu/drm/xe/xe_ras.h b/drivers/gpu/drm/xe/xe_ras.h index ea90593b62dc..ba0b0224df23 100644 --- a/drivers/gpu/drm/xe/xe_ras.h +++ b/drivers/gpu/drm/xe/xe_ras.h @@ -6,10 +6,15 @@ #ifndef _XE_RAS_H_ #define _XE_RAS_H_ +#include + struct xe_device; struct xe_sysctrl_event_response; void xe_ras_counter_threshold_crossed(struct xe_device *xe, struct xe_sysctrl_event_response *response); +int xe_ras_get_counter(struct xe_device *xe, u8 severity, u8 component, u32 *value); +int xe_ras_clear_counter(struct xe_device *xe, u8 severity, u8 component); +void xe_ras_init(struct xe_device *xe); #endif diff --git a/drivers/gpu/drm/xe/xe_ras_types.h b/drivers/gpu/drm/xe/xe_ras_types.h index 4e63c67f806a..6688e11f57a8 100644 --- a/drivers/gpu/drm/xe/xe_ras_types.h +++ b/drivers/gpu/drm/xe/xe_ras_types.h @@ -70,4 +70,55 @@ struct xe_ras_threshold_crossed { struct xe_ras_error_class counters[XE_RAS_NUM_COUNTERS]; } __packed; +/** + * struct xe_ras_get_counter_request - Request structure for get counter + */ +struct xe_ras_get_counter_request { + /** @counter: Error counter to be queried */ + struct xe_ras_error_class counter; + /** @reserved: Reserved for future use */ + u32 reserved; +} __packed; + +/** + * struct xe_ras_get_counter_response - Response structure for get counter + */ +struct xe_ras_get_counter_response { + /** @counter: Error counter that was queried */ + struct xe_ras_error_class counter; + /** @value: Current counter value */ + u32 value; + /** @timestamp: Timestamp when counter was last updated */ + u64 timestamp; + /** @threshold: Threshold value for the counter */ + u32 threshold; + /** @reserved: Reserved */ + u32 reserved[57]; +} __packed; + +/** + * struct xe_ras_clear_counter_request - Request structure for clear counter + */ +struct xe_ras_clear_counter_request { + /** @counter: Counter class to be cleared */ + struct xe_ras_error_class counter; + /** @reserved: Reserved for future use */ + u32 reserved; +} __packed; + +/** + * struct xe_ras_clear_counter_response - Response structure for clear counter + */ +struct xe_ras_clear_counter_response { + /** @counter: Counter class that was cleared */ + struct xe_ras_error_class counter; + /** @reserved: Reserved */ + u32 reserved; + /** @timestamp: Timestamp when the counter was cleared */ + u64 timestamp; + /** @status: Status of the clear operation */ + u32 status; + /** @reserved1: Reserved for future use */ + u32 reserved1[3]; +} __packed; #endif diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c index fb65940848d7..cab1b578ca0e 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c @@ -5,6 +5,8 @@ #include "xe_reg_whitelist.h" +#include + #include "regs/xe_engine_regs.h" #include "regs/xe_gt_regs.h" #include "regs/xe_oa_regs.h" @@ -41,7 +43,7 @@ static bool match_multi_queue_class(const struct xe_device *xe, return xe_gt_supports_multi_queue(gt, hwe->class); } -static const struct xe_rtp_entry_sr register_whitelist[] = { +VISIBLE_IF_KUNIT const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR( { XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(WHITELIST(PS_INVOCATION_COUNT, @@ -103,11 +105,17 @@ static const struct xe_rtp_entry_sr register_whitelist[] = { WHITELIST(VFLSKPD, RING_FORCE_TO_NONPRIV_ACCESS_RW)) }, +); +EXPORT_SYMBOL_IF_KUNIT(register_whitelist); + +static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR( + +#define WHITELIST_DENY(r, f) WHITELIST(r, (f) | RING_FORCE_TO_NONPRIV_DENY) #define WHITELIST_OA_MMIO_TRG(trg, status, head) \ - WHITELIST(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \ - WHITELIST(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \ - WHITELIST(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4) + WHITELIST_DENY(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \ + WHITELIST_DENY(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \ + WHITELIST_DENY(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4) #define WHITELIST_OAG_MMIO_TRG \ WHITELIST_OA_MMIO_TRG(OAG_MMIOTRIGGER, OAG_OASTATUS, OAG_OAHEADPTR) @@ -124,7 +132,7 @@ static const struct xe_rtp_entry_sr register_whitelist[] = { OAM_HEAD_POINTER(XE_OAM_SCMI_1_BASE_ADJ)) #define WHITELIST_OA_MERT_MMIO_TRG \ - WHITELIST_OA_MMIO_TRG(OAMERT_MMIO_TRG, OAMERT_STATUS, OAMERT_HEAD_POINTER) + WHITELIST_OA_MMIO_TRG(OAMERT_MMIO_TRG, OAMERT_STATUS, OAMERT_TAIL_POINTER) { XE_RTP_NAME("oag_mmio_trg_rcs"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, XE_RTP_END_VERSION_UNDEFINED), @@ -154,11 +162,12 @@ static const struct xe_rtp_entry_sr register_whitelist[] = { XE_RTP_RULES(FUNC(match_has_mert), ENGINE_CLASS(COPY)), XE_RTP_ACTIONS(WHITELIST_OA_MERT_MMIO_TRG) }, -}; +); -static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) +static int whitelist_apply_to_hwe(struct xe_hw_engine *hwe, struct xe_reg_sr *in, + struct xe_reg_sr *out, int first_slot) { - struct xe_reg_sr *sr = &hwe->reg_whitelist; + struct xe_reg_sr *sr = in; struct xe_reg_sr_entry *entry; struct drm_printer p; unsigned long reg; @@ -167,7 +176,7 @@ static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) xe_gt_dbg(hwe->gt, "Add %s whitelist to engine\n", sr->name); p = xe_gt_dbg_printer(hwe->gt); - slot = 0; + slot = first_slot; xa_for_each(&sr->xa, reg, entry) { struct xe_reg_sr_entry hwe_entry = { .reg = RING_FORCE_TO_NONPRIV(hwe->mmio_base, slot), @@ -184,10 +193,12 @@ static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) } xe_reg_whitelist_print_entry(&p, 0, reg, entry); - xe_reg_sr_add(&hwe->reg_sr, &hwe_entry, hwe->gt); + xe_reg_sr_add(out, &hwe_entry, hwe->gt); slot++; } + + return slot; } /** @@ -201,10 +212,78 @@ static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe) { struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); + int first_oa_slot; - xe_rtp_process_to_sr(&ctx, register_whitelist, ARRAY_SIZE(register_whitelist), - &hwe->reg_whitelist, false); - whitelist_apply_to_hwe(hwe); + xe_rtp_process_to_sr(&ctx, ®ister_whitelist, &hwe->reg_whitelist, false); + first_oa_slot = whitelist_apply_to_hwe(hwe, &hwe->reg_whitelist, &hwe->reg_sr, 0); + + xe_rtp_process_to_sr(&ctx, &oa_whitelist, &hwe->oa_whitelist, false); + + /* + * Save oa nonpriv registers to hwe->oa_sr, from which oa registers are whitelisted + * or de-whitelisted, by toggling the 'deny' bit on oa stream open/close + */ + whitelist_apply_to_hwe(hwe, &hwe->oa_whitelist, &hwe->oa_sr, first_oa_slot); + + /* + * Also save oa nonpriv registers to hwe->reg_sr, to ensure oa registers are not + * whitelisted by default after probe, gt reset, resume and engine reset + */ + whitelist_apply_to_hwe(hwe, &hwe->oa_whitelist, &hwe->reg_sr, first_oa_slot); +} + +static void __whitelist_oa_regs(struct xe_hw_engine *hwe, bool whitelist) +{ + struct xe_reg_sr_entry *entry; + unsigned long reg; + + xa_for_each(&hwe->oa_sr.xa, reg, entry) { + if (whitelist) + entry->set_bits &= ~RING_FORCE_TO_NONPRIV_DENY; + else + entry->set_bits |= RING_FORCE_TO_NONPRIV_DENY; + } + + xe_reg_sr_apply_mmio(&hwe->oa_sr, hwe->gt); +} + +/** + * xe_reg_whitelist_oa_regs - whitelist oa registers for gt + * @gt: gt to whitelist oa registers for + * + * Whitelist OA registers by resetting RING_FORCE_TO_NONPRIV_DENY + */ +void xe_reg_whitelist_oa_regs(struct xe_gt *gt) +{ + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + + lockdep_assert_held(>->oa.gt_lock); + if (gt->oa.whitelist_count++) + return; + + for_each_hw_engine(hwe, gt, id) + __whitelist_oa_regs(hwe, true); +} + +/** + * xe_reg_dewhitelist_oa_regs - dewhitelist oa registers for gt + * @gt: gt to dewhitelist oa registers for + * + * Dewhitelist OA registers by setting RING_FORCE_TO_NONPRIV_DENY + */ +void xe_reg_dewhitelist_oa_regs(struct xe_gt *gt) +{ + struct xe_hw_engine *hwe; + enum xe_hw_engine_id id; + + lockdep_assert_held(>->oa.gt_lock); + xe_assert(gt_to_xe(gt), gt->oa.whitelist_count); + if (--gt->oa.whitelist_count) + return; + + for_each_hw_engine(hwe, gt, id) + __whitelist_oa_regs(hwe, false); } /** diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.h b/drivers/gpu/drm/xe/xe_reg_whitelist.h index 3b64b42fe96e..c0248063d515 100644 --- a/drivers/gpu/drm/xe/xe_reg_whitelist.h +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.h @@ -9,12 +9,20 @@ #include struct drm_printer; +struct xe_gt; struct xe_hw_engine; struct xe_reg_sr; struct xe_reg_sr_entry; +#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) +extern const struct xe_rtp_table_sr register_whitelist; +#endif + void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe); +void xe_reg_whitelist_oa_regs(struct xe_gt *gt); +void xe_reg_dewhitelist_oa_regs(struct xe_gt *gt); + void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, u32 reg, struct xe_reg_sr_entry *entry); diff --git a/drivers/gpu/drm/xe/xe_rtp.c b/drivers/gpu/drm/xe/xe_rtp.c index dec9d94e6fb0..6a8d6ea68f25 100644 --- a/drivers/gpu/drm/xe/xe_rtp.c +++ b/drivers/gpu/drm/xe/xe_rtp.c @@ -227,17 +227,23 @@ static bool rule_matches(const struct xe_device *xe, static void rtp_add_sr_entry(const struct xe_rtp_action *action, struct xe_gt *gt, + struct xe_hw_engine *hwe, u32 mmio_base, struct xe_reg_sr *sr) { struct xe_reg_sr_entry sr_entry = { .reg = action->reg, .clr_bits = action->clr_bits, - .set_bits = action->set_bits, .read_mask = action->read_mask, }; + if (action->use_func) + sr_entry.set_bits = action->set_func(gt, hwe); + else + sr_entry.set_bits = action->set_bits; + sr_entry.reg.addr += mmio_base; + xe_reg_sr_add(sr, &sr_entry, gt); } @@ -259,7 +265,7 @@ static bool rtp_process_one_sr(const struct xe_rtp_entry_sr *entry, else mmio_base = 0; - rtp_add_sr_entry(action, gt, mmio_base, sr); + rtp_add_sr_entry(action, gt, hwe, mmio_base, sr); } return true; @@ -326,8 +332,7 @@ static void rtp_mark_active(struct xe_device *xe, * xe_rtp_process_to_sr - Process all rtp @entries, adding the matching ones to * the save-restore argument. * @ctx: The context for processing the table, with one of device, gt or hwe - * @entries: Table with RTP definitions - * @n_entries: Number of entries to process, usually ARRAY_SIZE(entries) + * @table: Table with RTP definitions * @sr: Save-restore struct where matching rules execute the action. This can be * viewed as the "coalesced view" of multiple the tables. The bits for each * register set are expected not to collide with previously added entries @@ -339,12 +344,10 @@ static void rtp_mark_active(struct xe_device *xe, * used to calculate the right register offset */ void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry_sr *entries, - size_t n_entries, + const struct xe_rtp_table_sr *table, struct xe_reg_sr *sr, bool process_in_vf) { - const struct xe_rtp_entry_sr *entry; struct xe_hw_engine *hwe = NULL; struct xe_gt *gt = NULL; struct xe_device *xe = NULL; @@ -354,9 +357,10 @@ void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, if (!process_in_vf && IS_SRIOV_VF(xe)) return; - xe_assert(xe, entries); + xe_assert(xe, table->entries); - for (entry = entries; entry - entries < n_entries; entry++) { + for (size_t i = 0; i < table->n_entries; i++) { + const struct xe_rtp_entry_sr *entry = &table->entries[i]; bool match = false; if (entry->flags & XE_RTP_ENTRY_FLAG_FOREACH_ENGINE) { @@ -371,37 +375,40 @@ void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, } if (match) - rtp_mark_active(xe, ctx, entry - entries); + rtp_mark_active(xe, ctx, i); } } EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process_to_sr); /** - * xe_rtp_process - Process all rtp @entries, without running any action + * xe_rtp_process - Process all entries in rtp @table, without running any action * @ctx: The context for processing the table, with one of device, gt or hwe - * @entries: Table with RTP definitions + * @table: Table with RTP definitions * - * Walk the table pointed by @entries (with an empty sentinel), executing the + * Walk the table pointed by @table, executing the * rules. One difference from xe_rtp_process_to_sr(): there is no action * associated with each entry since this uses struct xe_rtp_entry. Its main use * is for marking active workarounds via * xe_rtp_process_ctx_enable_active_tracking(). */ void xe_rtp_process(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry *entries) + const struct xe_rtp_table *table) { - const struct xe_rtp_entry *entry; struct xe_hw_engine *hwe; struct xe_gt *gt; struct xe_device *xe; rtp_get_context(ctx, &hwe, >, &xe); - for (entry = entries; entry && entry->rules; entry++) { + xe_assert(xe, table->entries); + + for (size_t i = 0; i < table->n_entries; i++) { + const struct xe_rtp_entry *entry = &table->entries[i]; + if (!rule_matches(xe, gt, hwe, entry->rules, entry->n_rules)) continue; - rtp_mark_active(xe, ctx, entry - entries); + rtp_mark_active(xe, ctx, i); } } EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process); diff --git a/drivers/gpu/drm/xe/xe_rtp.h b/drivers/gpu/drm/xe/xe_rtp.h index e4f1930ca1c3..0032f68ea187 100644 --- a/drivers/gpu/drm/xe/xe_rtp.h +++ b/drivers/gpu/drm/xe/xe_rtp.h @@ -322,6 +322,25 @@ struct xe_reg_sr; .clr_bits = (mask_bits_), .set_bits = (val_), \ .read_mask = 0, ##__VA_ARGS__ } +/** + * XE_RTP_ACTION_FIELD_SET_FUNC: Set a bit range to the value returned by a function + * @reg_: Register + * @mask_bits_: Mask of bits to be changed in the register, forming a field + * @func_: Function that returns value to set in the field denoted by @mask_bits_ + * @...: Additional fields to override in the struct xe_rtp_action entry + * + * This macro works like XE_RTP_ACTION_FIELD_SET(), except that the + * field value is evaluated at the time the RTP table is processed. + * + * @func_ will only be called a single time, when the RTP table is being + * processed. After processing, the value in the reg_sr entry is fixed and + * will not be re-evaluated. + */ +#define XE_RTP_ACTION_FIELD_SET_FUNC(reg_, mask_bits_, func_, ...) \ + { .reg = XE_RTP_DROP_CAST(reg_), \ + .clr_bits = mask_bits_, .set_func = func_, .use_func = 1, \ + .read_mask = mask_bits_, ##__VA_ARGS__ } + /** * XE_RTP_ACTION_WHITELIST - Add register to userspace whitelist * @reg_: Register @@ -461,6 +480,24 @@ struct xe_reg_sr; XE_RTP_PASTE_FOREACH(ACTION_, COMMA, (__VA_ARGS__)) \ } +/* + * Note: ARRAY_SIZE() cannot be used here because it expands through + * __must_be_array() -> __BUILD_BUG_ON_ZERO_MSG() -> _Static_assert inside + * sizeof(struct{}), which clang < 21 rejects when the compound literal + * contains non-compile-time-constant initializers. + */ +#define XE_RTP_TABLE_SR(...) { \ + .entries = (const struct xe_rtp_entry_sr[]){__VA_ARGS__}, \ + .n_entries = sizeof((const struct xe_rtp_entry_sr[]){__VA_ARGS__}) / \ + sizeof(struct xe_rtp_entry_sr), \ +} + +#define XE_RTP_TABLE(...) { \ + .entries = (const struct xe_rtp_entry[]){__VA_ARGS__}, \ + .n_entries = sizeof((const struct xe_rtp_entry[]){__VA_ARGS__}) / \ + sizeof(struct xe_rtp_entry), \ +} + #define XE_RTP_PROCESS_CTX_INITIALIZER(arg__) _Generic((arg__), \ struct xe_hw_engine * : (struct xe_rtp_process_ctx){ { (void *)(arg__) }, XE_RTP_PROCESS_TYPE_ENGINE }, \ struct xe_gt * : (struct xe_rtp_process_ctx){ { (void *)(arg__) }, XE_RTP_PROCESS_TYPE_GT }, \ @@ -471,12 +508,12 @@ void xe_rtp_process_ctx_enable_active_tracking(struct xe_rtp_process_ctx *ctx, size_t n_entries); void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry_sr *entries, - size_t n_entries, struct xe_reg_sr *sr, + const struct xe_rtp_table_sr *table, + struct xe_reg_sr *sr, bool process_in_vf); void xe_rtp_process(struct xe_rtp_process_ctx *ctx, - const struct xe_rtp_entry *entries); + const struct xe_rtp_table *table); /* Match functions to be used with XE_RTP_MATCH_FUNC */ diff --git a/drivers/gpu/drm/xe/xe_rtp_types.h b/drivers/gpu/drm/xe/xe_rtp_types.h index 0265c16d2762..b78092fa06e0 100644 --- a/drivers/gpu/drm/xe/xe_rtp_types.h +++ b/drivers/gpu/drm/xe/xe_rtp_types.h @@ -22,20 +22,37 @@ struct xe_gt; */ struct xe_rtp_action { /** @reg: Register */ - struct xe_reg reg; + struct xe_reg reg; + /** * @clr_bits: bits to clear when updating register. It's always a * superset of bits being modified */ - u32 clr_bits; - /** @set_bits: bits to set when updating register */ - u32 set_bits; + u32 clr_bits; + + union { + /** @set_bits: bits to set when updating register */ + u32 set_bits; + + /** @set_func: function to provide bits to set when updating register */ + u32 (*set_func)(struct xe_gt *gt, + struct xe_hw_engine *hwe); + }; + #define XE_RTP_NOCHECK .read_mask = 0 /** @read_mask: mask for bits to consider when reading value back */ - u32 read_mask; + u32 read_mask; + #define XE_RTP_ACTION_FLAG_ENGINE_BASE BIT(0) /** @flags: flags to apply on rule evaluation or action */ - u8 flags; + u8 flags; + + /** + * @use_func: + * Internal flag indicating @set_func should be called instead of + * using @set_bits. + */ + u8 use_func:1; }; enum { @@ -69,6 +86,7 @@ struct xe_rtp_rule { u8 platform; u8 subplatform; }; + /* * MATCH_GRAPHICS_VERSION / XE_RTP_MATCH_GRAPHICS_VERSION_RANGE / * MATCH_MEDIA_VERSION / XE_RTP_MATCH_MEDIA_VERSION_RANGE @@ -78,15 +96,18 @@ struct xe_rtp_rule { #define XE_RTP_END_VERSION_UNDEFINED U32_MAX u32 ver_end; }; + /* MATCH_STEP */ struct { u8 step_start; u8 step_end; }; + /* MATCH_ENGINE_CLASS / MATCH_NOT_ENGINE_CLASS */ struct { u8 engine_class; }; + /* MATCH_FUNC */ bool (*match_func)(const struct xe_device *xe, const struct xe_gt *gt, @@ -112,6 +133,16 @@ struct xe_rtp_entry { u8 n_rules; }; +struct xe_rtp_table_sr { + const struct xe_rtp_entry_sr *entries; + size_t n_entries; +}; + +struct xe_rtp_table { + const struct xe_rtp_entry *entries; + size_t n_entries; +}; + enum xe_rtp_process_type { XE_RTP_PROCESS_TYPE_DEVICE, XE_RTP_PROCESS_TYPE_GT, diff --git a/drivers/gpu/drm/xe/xe_step.c b/drivers/gpu/drm/xe/xe_step.c index fb9c31613ca7..55c1996f689e 100644 --- a/drivers/gpu/drm/xe/xe_step.c +++ b/drivers/gpu/drm/xe/xe_step.c @@ -110,12 +110,14 @@ __diag_pop(); /** * xe_step_platform_get - Determine platform-level stepping from PCI revid - * @xe: Xe device + * @platform: The Xe platform + * @revid: The PCI revid + * @step: Pointer to the step struct to update * * Convert the PCI revid into a platform-level stepping value and store that - * in the device info. + * in @step->platform. */ -void xe_step_platform_get(struct xe_device *xe) +void xe_step_platform_get(enum xe_platform platform, u8 revid, struct xe_step_info *step) { /* * Not all platforms map PCI revid directly into our symbolic stepping @@ -126,18 +128,21 @@ void xe_step_platform_get(struct xe_device *xe) * checks. */ - if (xe->info.platform == XE_NOVALAKE_P) - xe->info.step.platform = STEP_A0 + xe->info.revid; + if (platform == XE_NOVALAKE_P) + step->platform = STEP_A0 + revid; } /** * xe_step_pre_gmdid_get - Determine IP steppings from PCI revid * @xe: Xe device + * @step: Pointer to the step struct to update * - * Convert the PCI revid into proper IP steppings. This should only be - * used on platforms that do not have GMD_ID support. + * Convert the PCI revid into proper IP steppings and update @step->basedie, + * @step->graphics and @step->media accordingly. + * + * This should only be used on platforms that do not have GMD_ID support. */ -void xe_step_pre_gmdid_get(struct xe_device *xe) +void xe_step_pre_gmdid_get(struct xe_device *xe, struct xe_step_info *step) { const struct xe_step_info *revids = NULL; u16 revid = xe->info.revid; @@ -234,9 +239,9 @@ void xe_step_pre_gmdid_get(struct xe_device *xe) } done: - xe->info.step.graphics = graphics; - xe->info.step.media = media; - xe->info.step.basedie = basedie; + step->graphics = graphics; + step->media = media; + step->basedie = basedie; } /** @@ -244,8 +249,10 @@ void xe_step_pre_gmdid_get(struct xe_device *xe) * @xe: Xe device * @graphics_gmdid_revid: value of graphics GMD_ID register's revid field * @media_gmdid_revid: value of media GMD_ID register's revid field + * @step: Poninter to the step struct to update. * - * Convert the revid fields of the GMD_ID registers into proper IP steppings. + * Convert the revid fields of the GMD_ID registers into proper IP steppings + * and update @step->graphics and @step->media accordingly. * * GMD_ID revid values are currently expected to have consistent meanings on * all platforms: major steppings (A0, B0, etc.) are 4 apart, with minor @@ -253,7 +260,8 @@ void xe_step_pre_gmdid_get(struct xe_device *xe) */ void xe_step_gmdid_get(struct xe_device *xe, u32 graphics_gmdid_revid, - u32 media_gmdid_revid) + u32 media_gmdid_revid, + struct xe_step_info *step) { u8 graphics = STEP_A0 + graphics_gmdid_revid; u8 media = STEP_A0 + media_gmdid_revid; @@ -270,8 +278,8 @@ void xe_step_gmdid_get(struct xe_device *xe, media_gmdid_revid); } - xe->info.step.graphics = graphics; - xe->info.step.media = media; + step->graphics = graphics; + step->media = media; } #define STEP_NAME_CASE(name) \ diff --git a/drivers/gpu/drm/xe/xe_step.h b/drivers/gpu/drm/xe/xe_step.h index ea36b22cc297..5a5845335740 100644 --- a/drivers/gpu/drm/xe/xe_step.h +++ b/drivers/gpu/drm/xe/xe_step.h @@ -10,14 +10,16 @@ #include "xe_step_types.h" +enum xe_platform; struct xe_device; -void xe_step_platform_get(struct xe_device *xe); +void xe_step_platform_get(enum xe_platform platform, u8 revid, struct xe_step_info *step); -void xe_step_pre_gmdid_get(struct xe_device *xe); +void xe_step_pre_gmdid_get(struct xe_device *xe, struct xe_step_info *step); void xe_step_gmdid_get(struct xe_device *xe, u32 graphics_gmdid_revid, - u32 media_gmdid_revid); + u32 media_gmdid_revid, + struct xe_step_info *step); static inline u32 xe_step_to_gmdid(enum intel_step step) { return step - STEP_A0; } const char *xe_step_name(enum intel_step step); diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index dba73786d82a..e0f0c23d172d 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -1248,10 +1248,8 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma, xe_svm_range_fault_count_stats_incr(gt, range); - if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) { - err = -EACCES; - goto out; - } + if (ctx.devmem_only && !range->base.pages.flags.migrate_devmem) + return -EACCES; if (xe_svm_range_is_valid(range, tile, ctx.devmem_only, dpagemap)) { xe_svm_range_valid_fault_count_stats_incr(gt, range); diff --git a/drivers/gpu/drm/xe/xe_svm.h b/drivers/gpu/drm/xe/xe_svm.h index b7b8eeacf196..3ca46a6f98c7 100644 --- a/drivers/gpu/drm/xe/xe_svm.h +++ b/drivers/gpu/drm/xe/xe_svm.h @@ -394,8 +394,19 @@ static inline struct drm_pagemap *xe_drm_pagemap_from_fd(int fd, u32 region_inst #define xe_svm_assert_in_notifier(vm__) \ lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock) -#define xe_svm_assert_held_read(vm__) \ +/* + * Assert the svm notifier_lock is held. Read mode by default; write mode + * when CONFIG_DRM_XE_USERPTR_INVAL_INJECT is on, because that path forces + * a userptr invalidation that ends in drm_gpusvm_unmap_pages() with + * ctx->in_notifier=true, which requires the lock held for write. + */ +#if IS_ENABLED(CONFIG_DRM_XE_USERPTR_INVAL_INJECT) +#define xe_svm_assert_held_read_or_inject_write(vm__) \ + lockdep_assert_held_write(&(vm__)->svm.gpusvm.notifier_lock) +#else +#define xe_svm_assert_held_read_or_inject_write(vm__) \ lockdep_assert_held_read(&(vm__)->svm.gpusvm.notifier_lock) +#endif #define xe_svm_notifier_lock(vm__) \ drm_gpusvm_notifier_lock(&(vm__)->svm.gpusvm) @@ -409,7 +420,7 @@ static inline struct drm_pagemap *xe_drm_pagemap_from_fd(int fd, u32 region_inst #else #define xe_svm_assert_in_notifier(...) do {} while (0) -static inline void xe_svm_assert_held_read(struct xe_vm *vm) +static inline void xe_svm_assert_held_read_or_inject_write(struct xe_vm *vm) { } diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c index 3caa9f15875f..e13eebaac1d0 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c @@ -293,6 +293,34 @@ static int sysctrl_send_command(struct xe_sysctrl *sc, return 0; } +/** + * xe_sysctrl_create_command() - Create system controller command + * @command: Sysctrl command structure + * @group_id: Command group ID + * @cmd_id: Command ID + * @request: Pointer to request buffer (can be NULL) + * @request_len: Size of request buffer + * @response: Pointer to response buffer + * @response_len: Size of response buffer + * + * Helper function to create sysctrl command to be sent via %xe_sysctrl_send_command() + */ +void xe_sysctrl_create_command(struct xe_sysctrl_mailbox_command *command, u8 group_id, u8 cmd_id, + void *request, size_t request_len, void *response, + size_t response_len) +{ + struct xe_sysctrl_app_msg_hdr header = {0}; + + header.data = FIELD_PREP(APP_HDR_GROUP_ID_MASK, group_id) | + FIELD_PREP(APP_HDR_COMMAND_MASK, cmd_id); + + command->header = header; + command->data_in = request; + command->data_in_len = request_len; + command->data_out = response; + command->data_out_len = response_len; +} + /** * xe_sysctrl_mailbox_init - Initialize System Controller mailbox interface * @sc: System controller structure diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h index f67e9234de48..fb434cc165b2 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h @@ -23,6 +23,9 @@ struct xe_sysctrl_mailbox_command; #define XE_SYSCTRL_APP_HDR_VERSION(hdr) \ FIELD_GET(APP_HDR_VERSION_MASK, (hdr)->data) +void xe_sysctrl_create_command(struct xe_sysctrl_mailbox_command *command, u8 group_id, u8 cmd_id, + void *request, size_t request_len, void *response, + size_t response_len); void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc); int xe_sysctrl_send_command(struct xe_sysctrl *sc, struct xe_sysctrl_mailbox_command *cmd, diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h index 84d7c647e743..6e3753554510 100644 --- a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h @@ -22,9 +22,13 @@ enum xe_sysctrl_group { /** * enum xe_sysctrl_gfsp_cmd - Commands supported by GFSP group * + * @XE_SYSCTRL_CMD_GET_COUNTER: Get error counter value + * @XE_SYSCTRL_CMD_CLEAR_COUNTER: Clear error counter value * @XE_SYSCTRL_CMD_GET_PENDING_EVENT: Retrieve pending event */ enum xe_sysctrl_gfsp_cmd { + XE_SYSCTRL_CMD_GET_COUNTER = 0x03, + XE_SYSCTRL_CMD_CLEAR_COUNTER = 0x04, XE_SYSCTRL_CMD_GET_PENDING_EVENT = 0x07, }; diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c index c465aae7883c..74d925a337b7 100644 --- a/drivers/gpu/drm/xe/xe_tile.c +++ b/drivers/gpu/drm/xe/xe_tile.c @@ -157,7 +157,9 @@ int xe_tile_init_early(struct xe_tile *tile, struct xe_device *xe, u8 id) if (err) return err; - xe_pcode_init(tile); + err = xe_pcode_init_early(tile); + if (err) + return err; return 0; } diff --git a/drivers/gpu/drm/xe/xe_tuning.c b/drivers/gpu/drm/xe/xe_tuning.c index 9a1b3862e192..bcec40ca2d35 100644 --- a/drivers/gpu/drm/xe/xe_tuning.c +++ b/drivers/gpu/drm/xe/xe_tuning.c @@ -20,7 +20,7 @@ #undef XE_REG_MCR #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1) -static const struct xe_rtp_entry_sr gt_tunings[] = { +VISIBLE_IF_KUNIT const struct xe_rtp_table_sr gt_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: Blend Fill Caching Optimization Disable"), XE_RTP_RULES(PLATFORM(DG2)), XE_RTP_ACTIONS(SET(XEHP_L3SCQREG7, BLEND_FILL_CACHING_OPT_DIS)) @@ -100,9 +100,10 @@ static const struct xe_rtp_entry_sr gt_tunings[] = { XE_RTP_ACTIONS(FIELD_SET(GAMSTLB_CTRL, BANK_HASH_MODE, BANK_HASH_4KB_MODE)) }, -}; +); +EXPORT_SYMBOL_IF_KUNIT(gt_tunings); -static const struct xe_rtp_entry_sr engine_tunings[] = { +static const struct xe_rtp_table_sr engine_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: L3 Hashing Mask"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), FUNC(xe_rtp_match_first_render_or_compute)), @@ -129,9 +130,9 @@ static const struct xe_rtp_entry_sr engine_tunings[] = { FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(TDL_TSL_CHICKEN2, TILEY_LOCALID)) }, -}; +); -static const struct xe_rtp_entry_sr lrc_tunings[] = { +static const struct xe_rtp_table_sr lrc_tunings = XE_RTP_TABLE_SR( { XE_RTP_NAME("Tuning: Windower HW Filtering"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3599), ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(XEHP_COMMON_SLICE_CHICKEN4, HW_FILTERING)) @@ -171,7 +172,7 @@ static const struct xe_rtp_entry_sr lrc_tunings[] = { XE_RTP_ACTIONS(FIELD_SET(FF_MODE, VS_HIT_MAX_VALUE_MASK, REG_FIELD_PREP(VS_HIT_MAX_VALUE_MASK, 0x3f))) }, -}; +); /** * xe_tuning_init - initialize gt with tunings bookkeeping @@ -185,9 +186,9 @@ int xe_tuning_init(struct xe_gt *gt) size_t n_lrc, n_engine, n_gt, total; unsigned long *p; - n_gt = BITS_TO_LONGS(ARRAY_SIZE(gt_tunings)); - n_engine = BITS_TO_LONGS(ARRAY_SIZE(engine_tunings)); - n_lrc = BITS_TO_LONGS(ARRAY_SIZE(lrc_tunings)); + n_gt = BITS_TO_LONGS(gt_tunings.n_entries); + n_engine = BITS_TO_LONGS(engine_tunings.n_entries); + n_lrc = BITS_TO_LONGS(lrc_tunings.n_entries); total = n_gt + n_engine + n_lrc; p = drmm_kzalloc(&xe->drm, sizeof(*p) * total, GFP_KERNEL); @@ -210,9 +211,8 @@ void xe_tuning_process_gt(struct xe_gt *gt) xe_rtp_process_ctx_enable_active_tracking(&ctx, gt->tuning_active.gt, - ARRAY_SIZE(gt_tunings)); - xe_rtp_process_to_sr(&ctx, gt_tunings, ARRAY_SIZE(gt_tunings), - >->reg_sr, false); + gt_tunings.n_entries); + xe_rtp_process_to_sr(&ctx, >_tunings, >->reg_sr, false); } EXPORT_SYMBOL_IF_KUNIT(xe_tuning_process_gt); @@ -222,9 +222,8 @@ void xe_tuning_process_engine(struct xe_hw_engine *hwe) xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->tuning_active.engine, - ARRAY_SIZE(engine_tunings)); - xe_rtp_process_to_sr(&ctx, engine_tunings, ARRAY_SIZE(engine_tunings), - &hwe->reg_sr, false); + engine_tunings.n_entries); + xe_rtp_process_to_sr(&ctx, &engine_tunings, &hwe->reg_sr, false); } EXPORT_SYMBOL_IF_KUNIT(xe_tuning_process_engine); @@ -242,9 +241,8 @@ void xe_tuning_process_lrc(struct xe_hw_engine *hwe) xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->tuning_active.lrc, - ARRAY_SIZE(lrc_tunings)); - xe_rtp_process_to_sr(&ctx, lrc_tunings, ARRAY_SIZE(lrc_tunings), - &hwe->reg_lrc, true); + lrc_tunings.n_entries); + xe_rtp_process_to_sr(&ctx, &lrc_tunings, &hwe->reg_lrc, true); } /** @@ -259,18 +257,18 @@ int xe_tuning_dump(struct xe_gt *gt, struct drm_printer *p) size_t idx; drm_printf(p, "GT Tunings\n"); - for_each_set_bit(idx, gt->tuning_active.gt, ARRAY_SIZE(gt_tunings)) - drm_printf_indent(p, 1, "%s\n", gt_tunings[idx].name); + for_each_set_bit(idx, gt->tuning_active.gt, gt_tunings.n_entries) + drm_printf_indent(p, 1, "%s\n", gt_tunings.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "Engine Tunings\n"); - for_each_set_bit(idx, gt->tuning_active.engine, ARRAY_SIZE(engine_tunings)) - drm_printf_indent(p, 1, "%s\n", engine_tunings[idx].name); + for_each_set_bit(idx, gt->tuning_active.engine, engine_tunings.n_entries) + drm_printf_indent(p, 1, "%s\n", engine_tunings.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "LRC Tunings\n"); - for_each_set_bit(idx, gt->tuning_active.lrc, ARRAY_SIZE(lrc_tunings)) - drm_printf_indent(p, 1, "%s\n", lrc_tunings[idx].name); + for_each_set_bit(idx, gt->tuning_active.lrc, lrc_tunings.n_entries) + drm_printf_indent(p, 1, "%s\n", lrc_tunings.entries[idx].name); return 0; } diff --git a/drivers/gpu/drm/xe/xe_tuning.h b/drivers/gpu/drm/xe/xe_tuning.h index d18e187debf6..869564e3e992 100644 --- a/drivers/gpu/drm/xe/xe_tuning.h +++ b/drivers/gpu/drm/xe/xe_tuning.h @@ -6,6 +6,8 @@ #ifndef _XE_TUNING_H_ #define _XE_TUNING_H_ +#include + struct drm_printer; struct xe_gt; struct xe_hw_engine; @@ -16,4 +18,8 @@ void xe_tuning_process_engine(struct xe_hw_engine *hwe); void xe_tuning_process_lrc(struct xe_hw_engine *hwe); int xe_tuning_dump(struct xe_gt *gt, struct drm_printer *p); +#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) +extern const struct xe_rtp_table_sr gt_tunings; +#endif + #endif diff --git a/drivers/gpu/drm/xe/xe_userptr.c b/drivers/gpu/drm/xe/xe_userptr.c index 2e45e42c648f..1d2ab678faf5 100644 --- a/drivers/gpu/drm/xe/xe_userptr.c +++ b/drivers/gpu/drm/xe/xe_userptr.c @@ -269,7 +269,7 @@ static const struct mmu_interval_notifier_ops vma_userptr_notifier_ops = { */ void xe_vma_userptr_force_invalidate(struct xe_userptr_vma *uvma) { - static struct mmu_interval_notifier_finish *finish; + struct mmu_interval_notifier_finish *finish; struct xe_vm *vm = xe_vma_vm(&uvma->vma); /* Protect against concurrent userptr pinning */ diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c index c4fb29004195..9e343f9aa44d 100644 --- a/drivers/gpu/drm/xe/xe_vm_madvise.c +++ b/drivers/gpu/drm/xe/xe_vm_madvise.c @@ -332,6 +332,20 @@ static int xe_vm_invalidate_madvise_range(struct xe_vm *vm, u64 start, u64 end) return err; } +/** + * madvise_range_needs_invalidation() - Check whether madvise needs invalidation + * @args: madvise ioctl arguments + * + * Purgeable state updates only touch VMA/BO metadata. PTEs stay valid and are + * zapped only if the BO is later purged. + * + * Return: true when the update needs PTE invalidation. + */ +static bool madvise_range_needs_invalidation(const struct drm_xe_madvise *args) +{ + return args->type != DRM_XE_VMA_ATTR_PURGEABLE_STATE; +} + static bool madvise_args_are_sane(struct xe_device *xe, const struct drm_xe_madvise *args) { if (XE_IOCTL_DBG(xe, !args)) @@ -708,8 +722,9 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args, &details); - err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr, - madvise_range.addr + args->range); + if (madvise_range_needs_invalidation(args)) + err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr, + madvise_range.addr + args->range); if (madvise_range.has_svm_userptr_vmas) xe_svm_notifier_unlock(vm); diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index cb811f8a7781..139434946f8f 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -130,7 +130,7 @@ __diag_push(); __diag_ignore_all("-Woverride-init", "Allow field overrides in table"); -static const struct xe_rtp_entry_sr gt_was[] = { +VISIBLE_IF_KUNIT const struct xe_rtp_table_sr gt_was = XE_RTP_TABLE_SR( /* Workarounds applying over a range of IPs */ { XE_RTP_NAME("14011060649"), @@ -293,7 +293,7 @@ static const struct xe_rtp_entry_sr gt_was[] = { XE_RTP_ACTIONS(SET(MMIOATSREQLIMIT_GAM_WALK_3D, DIS_ATS_WRONLY_PG)) }, - { XE_RTP_NAME("14026144927, 16029437861"), + { XE_RTP_NAME("14026144927, 16029437861, 14026127056"), XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0)), XE_RTP_ACTIONS(SET(L3SQCREG2, L3_SQ_DISABLE_COAMA_2WAY_COH | L3_SQ_DISABLE_COAMA)) @@ -306,9 +306,10 @@ static const struct xe_rtp_entry_sr gt_was[] = { XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0)), XE_RTP_ACTIONS(SET(GUC_INTR_CHICKEN, DISABLE_SIGNALING_ENGINES)) }, -}; +); +EXPORT_SYMBOL_IF_KUNIT(gt_was); -static const struct xe_rtp_entry_sr engine_was[] = { +static const struct xe_rtp_table_sr engine_was = XE_RTP_TABLE_SR( /* Workarounds applying over a range of IPs */ { XE_RTP_NAME("22010931296, 18011464164, 14010919138"), @@ -586,12 +587,12 @@ static const struct xe_rtp_entry_sr engine_was[] = { /* Xe3p_LPG*/ - { XE_RTP_NAME("22021149932"), + { XE_RTP_NAME("22021149932, 14026290593"), XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0), FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, SAMPLER_LD_LSC_DISABLE)) }, - { XE_RTP_NAME("14025676848"), + { XE_RTP_NAME("14025676848, 14026270459"), XE_RTP_RULES(GRAPHICS_VERSION(3510), GRAPHICS_STEP(A0, B0), FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, LSCFE_SAME_ADDRESS_ATOMICS_COALESCING_DISABLE)) @@ -614,9 +615,9 @@ static const struct xe_rtp_entry_sr engine_was[] = { FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(TDL_CHICKEN, BIT_APQ_OPT_DIS)) }, -}; +); -static const struct xe_rtp_entry_sr lrc_was[] = { +static const struct xe_rtp_table_sr lrc_was = XE_RTP_TABLE_SR( { XE_RTP_NAME("16011163337"), XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)), /* read verification is ignored due to 1608008084. */ @@ -794,21 +795,31 @@ static const struct xe_rtp_entry_sr lrc_was[] = { ENGINE_CLASS(RENDER)), XE_RTP_ACTIONS(SET(CHICKEN_RASTER_1, DIS_CLIP_NEGATIVE_BOUNDING_BOX)) }, -}; +); -static __maybe_unused const struct xe_rtp_entry oob_was[] = { +static const struct xe_rtp_entry oob_was_entries[] = { #include - {} }; -static_assert(ARRAY_SIZE(oob_was) - 1 == _XE_WA_OOB_COUNT); +static_assert(ARRAY_SIZE(oob_was_entries) == _XE_WA_OOB_COUNT); -static __maybe_unused const struct xe_rtp_entry device_oob_was[] = { +VISIBLE_IF_KUNIT __maybe_unused const struct xe_rtp_table oob_was = { + .entries = oob_was_entries, + .n_entries = ARRAY_SIZE(oob_was_entries), +}; +EXPORT_SYMBOL_IF_KUNIT(oob_was); + +static const struct xe_rtp_entry device_oob_was_entries[] = { #include - {} }; -static_assert(ARRAY_SIZE(device_oob_was) - 1 == _XE_DEVICE_WA_OOB_COUNT); +static_assert(ARRAY_SIZE(device_oob_was_entries) == _XE_DEVICE_WA_OOB_COUNT); + +VISIBLE_IF_KUNIT __maybe_unused const struct xe_rtp_table device_oob_was = { + .entries = device_oob_was_entries, + .n_entries = ARRAY_SIZE(device_oob_was_entries), +}; +EXPORT_SYMBOL_IF_KUNIT(device_oob_was); __diag_pop(); @@ -824,10 +835,10 @@ void xe_wa_process_device_oob(struct xe_device *xe) { struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(xe); - xe_rtp_process_ctx_enable_active_tracking(&ctx, xe->wa_active.oob, ARRAY_SIZE(device_oob_was)); + xe_rtp_process_ctx_enable_active_tracking(&ctx, xe->wa_active.oob, device_oob_was.n_entries); xe->wa_active.oob_initialized = true; - xe_rtp_process(&ctx, device_oob_was); + xe_rtp_process(&ctx, &device_oob_was); } /** @@ -842,9 +853,9 @@ void xe_wa_process_gt_oob(struct xe_gt *gt) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); xe_rtp_process_ctx_enable_active_tracking(&ctx, gt->wa_active.oob, - ARRAY_SIZE(oob_was)); + oob_was.n_entries); gt->wa_active.oob_initialized = true; - xe_rtp_process(&ctx, oob_was); + xe_rtp_process(&ctx, &oob_was); } /** @@ -859,9 +870,8 @@ void xe_wa_process_gt(struct xe_gt *gt) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); xe_rtp_process_ctx_enable_active_tracking(&ctx, gt->wa_active.gt, - ARRAY_SIZE(gt_was)); - xe_rtp_process_to_sr(&ctx, gt_was, ARRAY_SIZE(gt_was), - >->reg_sr, false); + gt_was.n_entries); + xe_rtp_process_to_sr(&ctx, >_was, >->reg_sr, false); } EXPORT_SYMBOL_IF_KUNIT(xe_wa_process_gt); @@ -878,9 +888,8 @@ void xe_wa_process_engine(struct xe_hw_engine *hwe) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->wa_active.engine, - ARRAY_SIZE(engine_was)); - xe_rtp_process_to_sr(&ctx, engine_was, ARRAY_SIZE(engine_was), - &hwe->reg_sr, false); + engine_was.n_entries); + xe_rtp_process_to_sr(&ctx, &engine_was, &hwe->reg_sr, false); } /** @@ -896,9 +905,8 @@ void xe_wa_process_lrc(struct xe_hw_engine *hwe) struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(hwe); xe_rtp_process_ctx_enable_active_tracking(&ctx, hwe->gt->wa_active.lrc, - ARRAY_SIZE(lrc_was)); - xe_rtp_process_to_sr(&ctx, lrc_was, ARRAY_SIZE(lrc_was), - &hwe->reg_lrc, true); + lrc_was.n_entries); + xe_rtp_process_to_sr(&ctx, &lrc_was, &hwe->reg_lrc, true); } /** @@ -912,7 +920,7 @@ int xe_wa_device_init(struct xe_device *xe) unsigned long *p; p = drmm_kzalloc(&xe->drm, - sizeof(*p) * BITS_TO_LONGS(ARRAY_SIZE(device_oob_was)), + sizeof(*p) * BITS_TO_LONGS(device_oob_was.n_entries), GFP_KERNEL); if (!p) @@ -935,10 +943,10 @@ int xe_wa_gt_init(struct xe_gt *gt) size_t n_oob, n_lrc, n_engine, n_gt, total; unsigned long *p; - n_gt = BITS_TO_LONGS(ARRAY_SIZE(gt_was)); - n_engine = BITS_TO_LONGS(ARRAY_SIZE(engine_was)); - n_lrc = BITS_TO_LONGS(ARRAY_SIZE(lrc_was)); - n_oob = BITS_TO_LONGS(ARRAY_SIZE(oob_was)); + n_gt = BITS_TO_LONGS(gt_was.n_entries); + n_engine = BITS_TO_LONGS(engine_was.n_entries); + n_lrc = BITS_TO_LONGS(lrc_was.n_entries); + n_oob = BITS_TO_LONGS(oob_was.n_entries); total = n_gt + n_engine + n_lrc + n_oob; p = drmm_kzalloc(&xe->drm, sizeof(*p) * total, GFP_KERNEL); @@ -962,9 +970,9 @@ void xe_wa_device_dump(struct xe_device *xe, struct drm_printer *p) size_t idx; drm_printf(p, "Device OOB Workarounds\n"); - for_each_set_bit(idx, xe->wa_active.oob, ARRAY_SIZE(device_oob_was)) - if (device_oob_was[idx].name) - drm_printf_indent(p, 1, "%s\n", device_oob_was[idx].name); + for_each_set_bit(idx, xe->wa_active.oob, device_oob_was.n_entries) + if (device_oob_was.entries[idx].name) + drm_printf_indent(p, 1, "%s\n", device_oob_was.entries[idx].name); } /** @@ -979,24 +987,24 @@ int xe_wa_gt_dump(struct xe_gt *gt, struct drm_printer *p) size_t idx; drm_printf(p, "GT Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.gt, ARRAY_SIZE(gt_was)) - drm_printf_indent(p, 1, "%s\n", gt_was[idx].name); + for_each_set_bit(idx, gt->wa_active.gt, gt_was.n_entries) + drm_printf_indent(p, 1, "%s\n", gt_was.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "Engine Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.engine, ARRAY_SIZE(engine_was)) - drm_printf_indent(p, 1, "%s\n", engine_was[idx].name); + for_each_set_bit(idx, gt->wa_active.engine, engine_was.n_entries) + drm_printf_indent(p, 1, "%s\n", engine_was.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "LRC Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.lrc, ARRAY_SIZE(lrc_was)) - drm_printf_indent(p, 1, "%s\n", lrc_was[idx].name); + for_each_set_bit(idx, gt->wa_active.lrc, lrc_was.n_entries) + drm_printf_indent(p, 1, "%s\n", lrc_was.entries[idx].name); drm_puts(p, "\n"); drm_printf(p, "OOB Workarounds\n"); - for_each_set_bit(idx, gt->wa_active.oob, ARRAY_SIZE(oob_was)) - if (oob_was[idx].name) - drm_printf_indent(p, 1, "%s\n", oob_was[idx].name); + for_each_set_bit(idx, gt->wa_active.oob, oob_was.n_entries) + if (oob_was.entries[idx].name) + drm_printf_indent(p, 1, "%s\n", oob_was.entries[idx].name); return 0; } diff --git a/drivers/gpu/drm/xe/xe_wa.h b/drivers/gpu/drm/xe/xe_wa.h index a5f7d33c1b32..f4da2b271396 100644 --- a/drivers/gpu/drm/xe/xe_wa.h +++ b/drivers/gpu/drm/xe/xe_wa.h @@ -6,6 +6,7 @@ #ifndef _XE_WA_H_ #define _XE_WA_H_ +#include #include "xe_assert.h" struct drm_printer; @@ -24,6 +25,12 @@ void xe_wa_apply_tile_workarounds(struct xe_tile *tile); void xe_wa_device_dump(struct xe_device *xe, struct drm_printer *p); int xe_wa_gt_dump(struct xe_gt *gt, struct drm_printer *p); +#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) +extern const struct xe_rtp_table_sr gt_was; +extern __maybe_unused const struct xe_rtp_table oob_was; +extern __maybe_unused const struct xe_rtp_table device_oob_was; +#endif + /** * XE_GT_WA - Out-of-band GT workarounds, to be queried and called as needed. * @gt__: gt instance diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index f8a185103b80..9027365f0043 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -65,3 +65,4 @@ 14025883347 MEDIA_VERSION_RANGE(1301, 3503) GRAPHICS_VERSION_RANGE(2004, 3005) +16029380221 MEDIA_VERSION(3500) diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c index 210f17c3a0be..83b9bc4b02e6 100644 --- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -9,7 +9,6 @@ #include #include -#include #include #include "i2c-hid.h" diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.h b/drivers/hid/intel-ish-hid/ishtp/bus.h index 53645ac89ee8..fa5e2797f1be 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.h +++ b/drivers/hid/intel-ish-hid/ishtp/bus.h @@ -8,7 +8,7 @@ #define _LINUX_ISHTP_CL_BUS_H #include -#include +#include #include struct ishtp_cl; diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c index 99904312879b..98810bfd1ca8 100644 --- a/drivers/hsi/controllers/omap_ssi_port.c +++ b/drivers/hsi/controllers/omap_ssi_port.c @@ -7,7 +7,6 @@ * Contact: Carlos Chinea */ -#include #include #include #include diff --git a/drivers/hte/hte-tegra194-test.c b/drivers/hte/hte-tegra194-test.c index 94e931f45305..32907d951ec9 100644 --- a/drivers/hte/hte-tegra194-test.c +++ b/drivers/hte/hte-tegra194-test.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 5c2d3ff5fce8..2bfbcc033d59 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1098,6 +1098,7 @@ config SENSORS_LTC2992 tristate "Linear Technology LTC2992" depends on I2C depends on GPIOLIB + select REGMAP_I2C help If you say yes here you get support for Linear Technology LTC2992 I2C System Monitor. The LTC2992 measures current, voltage, and @@ -1248,6 +1249,7 @@ config SENSORS_MAX16065 config SENSORS_MAX1619 tristate "Maxim MAX1619 sensor chip" depends on I2C + select REGMAP help If you say yes here you get support for MAX1619 sensor chip. @@ -1366,6 +1368,7 @@ config SENSORS_MAX6650 config SENSORS_MAX6697 tristate "Maxim MAX6697 and compatibles" depends on I2C + select REGMAP_I2C help If you say yes here you get support for MAX6581, MAX6602, MAX6622, MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699 diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c index de37bce24fa6..937fd9ef98b1 100644 --- a/drivers/hwmon/adcxx.c +++ b/drivers/hwmon/adcxx.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #define DRVNAME "adcxx" diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c index 0aa7ce0a04be..6629b83aab08 100644 --- a/drivers/hwmon/adt7410.c +++ b/drivers/hwmon/adt7410.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/hwmon/adt7462.c b/drivers/hwmon/adt7462.c index 31cf9e3bb04f..376331f7fa17 100644 --- a/drivers/hwmon/adt7462.c +++ b/drivers/hwmon/adt7462.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 7241fc73d21a..cd0b69ecb640 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/drivers/hwmon/as370-hwmon.c b/drivers/hwmon/as370-hwmon.c index 316454bd983d..702449c0fb86 100644 --- a/drivers/hwmon/as370-hwmon.c +++ b/drivers/hwmon/as370-hwmon.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #define CTRL 0x0 diff --git a/drivers/hwmon/aspeed-g6-pwm-tach.c b/drivers/hwmon/aspeed-g6-pwm-tach.c index 4f6e6d440dd4..5d611a8e5269 100644 --- a/drivers/hwmon/aspeed-g6-pwm-tach.c +++ b/drivers/hwmon/aspeed-g6-pwm-tach.c @@ -293,7 +293,10 @@ static int aspeed_tach_val_to_rpm(struct aspeed_pwm_tach_data *priv, u32 tach_va priv->clk_rate, tach_val, tach_div); rpm = (u64)priv->clk_rate * 60; - do_div(rpm, tach_div); + if (tach_div) + do_div(rpm, tach_div); + else + rpm = 0; return (int)rpm; } diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 109318b0434d..92afb64c09df 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -1037,6 +1037,9 @@ static int atk_ec_present(struct atk_data *data) if (obj->type != ACPI_TYPE_PACKAGE) continue; + if (!obj->package.count) + continue; + id = &obj->package.elements[0]; if (id->type != ACPI_TYPE_INTEGER) continue; diff --git a/drivers/hwmon/axi-fan-control.c b/drivers/hwmon/axi-fan-control.c index 01590dfa55e6..1cb481a1ad26 100644 --- a/drivers/hwmon/axi-fan-control.c +++ b/drivers/hwmon/axi-fan-control.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/hwmon/cros_ec_hwmon.c b/drivers/hwmon/cros_ec_hwmon.c index ea24056ae646..03bfcc40bb7c 100644 --- a/drivers/hwmon/cros_ec_hwmon.c +++ b/drivers/hwmon/cros_ec_hwmon.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/gxp-fan-ctrl.c b/drivers/hwmon/gxp-fan-ctrl.c index 00e057050437..86e7bafd3a38 100644 --- a/drivers/hwmon/gxp-fan-ctrl.c +++ b/drivers/hwmon/gxp-fan-ctrl.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #define OFS_FAN_INST 0 /* Is 0 because plreg base will be set at INST */ diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c index e376d4cde5ad..fc17ad93a376 100644 --- a/drivers/hwmon/iio_hwmon.c +++ b/drivers/hwmon/iio_hwmon.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/hwmon/intel-m10-bmc-hwmon.c b/drivers/hwmon/intel-m10-bmc-hwmon.c index e85d42a45113..d75303ed93e5 100644 --- a/drivers/hwmon/intel-m10-bmc-hwmon.c +++ b/drivers/hwmon/intel-m10-bmc-hwmon.c @@ -9,7 +9,6 @@ #include #include #include -#include #include struct m10bmc_sdata { diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c index 77fece680358..f6cae24cca9e 100644 --- a/drivers/hwmon/jc42.c +++ b/drivers/hwmon/jc42.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/hwmon/lan966x-hwmon.c b/drivers/hwmon/lan966x-hwmon.c index 7247c03e4f44..4071bc2afa32 100644 --- a/drivers/hwmon/lan966x-hwmon.c +++ b/drivers/hwmon/lan966x-hwmon.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 0d5a250cb672..8b525725fef4 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c index 104149a03bad..2d2d752aeac9 100644 --- a/drivers/hwmon/lm75.c +++ b/drivers/hwmon/lm75.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/ltc2947-core.c b/drivers/hwmon/ltc2947-core.c index ad7120d1e469..6eba857d4ef8 100644 --- a/drivers/hwmon/ltc2947-core.c +++ b/drivers/hwmon/ltc2947-core.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c index b9084424160d..39b9d3abca99 100644 --- a/drivers/hwmon/ltc4282.c +++ b/drivers/hwmon/ltc4282.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/ltc4283.c b/drivers/hwmon/ltc4283.c index d8931c9a4685..9b85293ea664 100644 --- a/drivers/hwmon/ltc4283.c +++ b/drivers/hwmon/ltc4283.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include diff --git a/drivers/hwmon/ltq-cputemp.c b/drivers/hwmon/ltq-cputemp.c index f7e4a4ca5239..b3424d72cb2b 100644 --- a/drivers/hwmon/ltq-cputemp.c +++ b/drivers/hwmon/ltq-cputemp.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 9b6ab050db1b..0d315087b504 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 66304d48d33a..b217b39a046a 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/mr75203.c b/drivers/hwmon/mr75203.c index 32c1e42e1278..449f2ce13a2d 100644 --- a/drivers/hwmon/mr75203.c +++ b/drivers/hwmon/mr75203.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 6f82a6c49393..1ac0288fbbd8 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 42cc6068bb08..e18e80e832fd 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -214,6 +214,11 @@ int occ_update_response(struct occ *occ) if (rc) return rc; + if (!occ->active) { + rc = -ENODEV; + goto unlock; + } + /* limit the maximum rate of polling the OCC */ if (time_after(jiffies, occ->next_update)) { rc = occ_poll(occ); @@ -222,6 +227,7 @@ int occ_update_response(struct occ *occ) rc = occ->last_error; } +unlock: mutex_unlock(&occ->lock); return rc; } @@ -1105,11 +1111,16 @@ static void occ_parse_poll_response(struct occ *occ) int occ_active(struct occ *occ, bool active) { - int rc = mutex_lock_interruptible(&occ->lock); + struct device *hwmon = NULL; + int rc = mutex_lock_interruptible(&occ->hwmon_lock); if (rc) return rc; + rc = mutex_lock_interruptible(&occ->lock); + if (rc) + goto unlock_hwmon; + if (active) { if (occ->active) { rc = -EALREADY; @@ -1154,14 +1165,17 @@ int occ_active(struct occ *occ, bool active) goto unlock; } - if (occ->hwmon) - hwmon_device_unregister(occ->hwmon); + hwmon = occ->hwmon; occ->active = false; occ->hwmon = NULL; } unlock: mutex_unlock(&occ->lock); + if (hwmon) + hwmon_device_unregister(hwmon); +unlock_hwmon: + mutex_unlock(&occ->hwmon_lock); return rc; } @@ -1170,6 +1184,7 @@ int occ_setup(struct occ *occ) int rc; mutex_init(&occ->lock); + mutex_init(&occ->hwmon_lock); occ->groups[0] = &occ->group; rc = occ_setup_sysfs(occ); @@ -1190,15 +1205,22 @@ EXPORT_SYMBOL_GPL(occ_setup); void occ_shutdown(struct occ *occ) { - mutex_lock(&occ->lock); + struct device *hwmon; occ_shutdown_sysfs(occ); - if (occ->hwmon) - hwmon_device_unregister(occ->hwmon); + mutex_lock(&occ->hwmon_lock); + mutex_lock(&occ->lock); + + hwmon = occ->hwmon; + occ->active = false; occ->hwmon = NULL; mutex_unlock(&occ->lock); + + if (hwmon) + hwmon_device_unregister(hwmon); + mutex_unlock(&occ->hwmon_lock); } EXPORT_SYMBOL_GPL(occ_shutdown); diff --git a/drivers/hwmon/occ/common.h b/drivers/hwmon/occ/common.h index 7ac4b2febce6..82f600093c7f 100644 --- a/drivers/hwmon/occ/common.h +++ b/drivers/hwmon/occ/common.h @@ -101,6 +101,7 @@ struct occ { unsigned long next_update; struct mutex lock; /* lock OCC access */ + struct mutex hwmon_lock; /* serialize hwmon registration/removal */ struct device *hwmon; struct occ_attribute *attrs; diff --git a/drivers/hwmon/occ/p9_sbe.c b/drivers/hwmon/occ/p9_sbe.c index 1e3749dfa598..4b4cbba58d79 100644 --- a/drivers/hwmon/occ/p9_sbe.c +++ b/drivers/hwmon/occ/p9_sbe.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 2e5963fb1e12..d3c3ff85dba3 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -512,7 +512,7 @@ static int adm1275_enable_vout_temp(struct adm1275_data *data, static int adm1275_probe(struct i2c_client *client) { s32 (*config_read_fn)(const struct i2c_client *client, u8 reg); - u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; + u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1] = {0}; int config, device_config; int ret; struct pmbus_driver_info *info; @@ -839,15 +839,25 @@ static int adm1275_probe(struct i2c_client *client) info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R; } if (cindex >= 0) { + u32 m; + /* Scale current with sense resistor value */ - info->m[PSC_CURRENT_OUT] = - coefficients[cindex].m * shunt / 1000; + if (unlikely(check_mul_overflow(coefficients[cindex].m, shunt, &m))) { + dev_err(&client->dev, "Current coefficient overflow\n"); + return -EOVERFLOW; + } + info->m[PSC_CURRENT_OUT] = m / 1000; info->b[PSC_CURRENT_OUT] = coefficients[cindex].b; info->R[PSC_CURRENT_OUT] = coefficients[cindex].R; } if (pindex >= 0) { - info->m[PSC_POWER] = - coefficients[pindex].m * shunt / 1000; + u32 m; + + if (unlikely(check_mul_overflow(coefficients[pindex].m, shunt, &m))) { + dev_err(&client->dev, "Power coefficient overflow\n"); + return -EOVERFLOW; + } + info->m[PSC_POWER] = m / 1000; info->b[PSC_POWER] = coefficients[pindex].b; info->R[PSC_POWER] = coefficients[pindex].R; } diff --git a/drivers/hwmon/pmbus/adp1050.c b/drivers/hwmon/pmbus/adp1050.c index a73774f8da2d..c3ad33024df9 100644 --- a/drivers/hwmon/pmbus/adp1050.c +++ b/drivers/hwmon/pmbus/adp1050.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include "pmbus.h" diff --git a/drivers/hwmon/pmbus/e50sn12051.c b/drivers/hwmon/pmbus/e50sn12051.c index efb4d62b2603..abad39bdbd37 100644 --- a/drivers/hwmon/pmbus/e50sn12051.c +++ b/drivers/hwmon/pmbus/e50sn12051.c @@ -5,7 +5,6 @@ #include #include -#include #include "pmbus.h" static struct pmbus_driver_info e50sn12051_info = { diff --git a/drivers/hwmon/pmbus/lt3074.c b/drivers/hwmon/pmbus/lt3074.c index ed932ddb4f77..a7f9edf02511 100644 --- a/drivers/hwmon/pmbus/lt3074.c +++ b/drivers/hwmon/pmbus/lt3074.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include "pmbus.h" diff --git a/drivers/hwmon/pmbus/max17616.c b/drivers/hwmon/pmbus/max17616.c index 744fa5aefe93..7636bbf06c6f 100644 --- a/drivers/hwmon/pmbus/max17616.c +++ b/drivers/hwmon/pmbus/max17616.c @@ -7,7 +7,6 @@ #include #include -#include #include #include "pmbus.h" diff --git a/drivers/hwmon/pmbus/max20830.c b/drivers/hwmon/pmbus/max20830.c index cb2c23672166..e3470118fd36 100644 --- a/drivers/hwmon/pmbus/max20830.c +++ b/drivers/hwmon/pmbus/max20830.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include "pmbus.h" diff --git a/drivers/hwmon/pmbus/mp2975.c b/drivers/hwmon/pmbus/mp2975.c index dca7e2fbcb44..5393f7aeea0f 100644 --- a/drivers/hwmon/pmbus/mp2975.c +++ b/drivers/hwmon/pmbus/mp2975.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "pmbus.h" diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index e8fdd799c71c..3143b9e0316c 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1095,9 +1095,27 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data, static u16 pmbus_data2reg_vid(struct pmbus_data *data, struct pmbus_sensor *sensor, s64 val) { - val = clamp_val(val, 500, 1600); - - return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); + switch (data->info->vrm_version[sensor->page]) { + case vr12: + val = clamp_val(val, 250, 1520); + return 1 + DIV_ROUND_CLOSEST_ULL(val - 250, 5); + case vr13: + val = clamp_val(val, 500, 3040); + return 1 + DIV_ROUND_CLOSEST_ULL(val - 500, 10); + case imvp9: + val = clamp_val(val, 200, 2740); + return 1 + DIV_ROUND_CLOSEST_ULL(val - 200, 10); + case amd625mv: + val = clamp_val(val, 200, 1550); + return DIV_ROUND_CLOSEST_ULL((1550LL - val) * 100LL, 625); + case nvidia195mv: + val = clamp_val(val, 195, 1465); + return 1 + DIV_ROUND_CLOSEST_ULL(val - 195, 5); + case vr11: + default: + val = clamp_val(val, 500, 1600); + return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625); + } } static u16 pmbus_data2reg(struct pmbus_data *data, @@ -3329,18 +3347,23 @@ static void pmbus_regulator_notify_worker(struct work_struct *work) int i, j; for (i = 0; i < data->info->pages; i++) { - int event; + unsigned int event; event = atomic_xchg(&data->regulator_events[i], 0); if (!event) continue; for (j = 0; j < data->info->num_regulators; j++) { - if (i == rdev_get_id(data->rdevs[j])) { + if (i != rdev_get_id(data->rdevs[j])) + continue; + while (event) { + unsigned int _event = BIT(__ffs(event)); + regulator_notifier_call_chain(data->rdevs[j], - event, NULL); - break; + _event, NULL); + event &= ~_event; } + break; } } } diff --git a/drivers/hwmon/pmbus/stef48h28.c b/drivers/hwmon/pmbus/stef48h28.c index 8e48dd3ba74b..6aa536c37c75 100644 --- a/drivers/hwmon/pmbus/stef48h28.c +++ b/drivers/hwmon/pmbus/stef48h28.c @@ -5,7 +5,6 @@ #include #include -#include #include #include "pmbus.h" diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index e6a567d58579..37f37813ea51 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 33e997b5c1f5..04e701ce2e74 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index d00bd5cc6b15..8c9b6e24d09f 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -7,7 +7,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include diff --git a/drivers/hwmon/sl28cpld-hwmon.c b/drivers/hwmon/sl28cpld-hwmon.c index 454cc844fb9d..9c83b4f2a34b 100644 --- a/drivers/hwmon/sl28cpld-hwmon.c +++ b/drivers/hwmon/sl28cpld-hwmon.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/smpro-hwmon.c b/drivers/hwmon/smpro-hwmon.c index d320adbd47f4..37d859f6c8f3 100644 --- a/drivers/hwmon/smpro-hwmon.c +++ b/drivers/hwmon/smpro-hwmon.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/sparx5-temp.c b/drivers/hwmon/sparx5-temp.c index d640904939cd..aa9178073744 100644 --- a/drivers/hwmon/sparx5-temp.c +++ b/drivers/hwmon/sparx5-temp.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 6bd1bed3cdb8..95fb912a1f7e 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #define DRIVER_NAME "tmp102" diff --git a/drivers/hwmon/tmp108.c b/drivers/hwmon/tmp108.c index 1c4a58855e2d..9fa31bd66ff6 100644 --- a/drivers/hwmon/tmp108.c +++ b/drivers/hwmon/tmp108.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 95115d7b863e..bb993bb09f40 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -1823,6 +1823,8 @@ static int w83627hf_probe(struct platform_device *pdev) return 0; error: + device_remove_file(dev, &dev_attr_vrm); + device_remove_file(dev, &dev_attr_cpu0_vid); sysfs_remove_group(&dev->kobj, &w83627hf_group); sysfs_remove_group(&dev->kobj, &w83627hf_group_opt); return err; @@ -1834,6 +1836,8 @@ static void w83627hf_remove(struct platform_device *pdev) hwmon_device_unregister(data->hwmon_dev); + device_remove_file(&pdev->dev, &dev_attr_vrm); + device_remove_file(&pdev->dev, &dev_attr_cpu0_vid); sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group); sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); } diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index b1f906f06ab4..a548586369e1 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -1917,6 +1917,7 @@ static int w83793_probe(struct i2c_client *client) for (i = 0; i < ARRAY_SIZE(w83793_vid); i++) device_remove_file(dev, &w83793_vid[i].dev_attr); + device_remove_file(dev, &dev_attr_vrm); for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++) device_remove_file(dev, &w83793_left_fan[i].dev_attr); diff --git a/drivers/hwtracing/coresight/ultrasoc-smb.c b/drivers/hwtracing/coresight/ultrasoc-smb.c index 20a950b9dd4f..b107d4606fcd 100644 --- a/drivers/hwtracing/coresight/ultrasoc-smb.c +++ b/drivers/hwtracing/coresight/ultrasoc-smb.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "coresight-etm-perf.h" diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c index ca45f0f23321..82cbc8fb5c18 100644 --- a/drivers/i2c/busses/i2c-amd-asf-plat.c +++ b/drivers/i2c/busses/i2c-amd-asf-plat.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c index 2d117e7e3cb6..f9a5465f52da 100644 --- a/drivers/i2c/busses/i2c-gxp.c +++ b/drivers/i2c/busses/i2c-gxp.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index 4b735ad9e193..04d7978cae04 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c index 8cedffbb2964..3a8225b0666c 100644 --- a/drivers/i2c/busses/i2c-rtl9300.c +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c index 238714850673..4ba8eaa322e5 100644 --- a/drivers/i2c/busses/i2c-rzv2m.c +++ b/drivers/i2c/busses/i2c-rzv2m.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 4797ba88331c..c519da536647 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -3,6 +3,7 @@ * i2c-core.h - interfaces internal to the I2C framework */ +#include #include #include diff --git a/drivers/iio/accel/adxl313_i2c.c b/drivers/iio/accel/adxl313_i2c.c index 6736b83f23bd..2eea8d4d044b 100644 --- a/drivers/iio/accel/adxl313_i2c.c +++ b/drivers/iio/accel/adxl313_i2c.c @@ -8,7 +8,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/accel/adxl313_spi.c b/drivers/iio/accel/adxl313_spi.c index d096ea0632ba..a61295de104f 100644 --- a/drivers/iio/accel/adxl313_spi.c +++ b/drivers/iio/accel/adxl313_spi.c @@ -7,7 +7,6 @@ * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf */ -#include #include #include #include diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 89ac62ff4d04..68cb2557f390 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/adxl355_i2c.c b/drivers/iio/accel/adxl355_i2c.c index 0b6b016bd358..e533a7aabd44 100644 --- a/drivers/iio/accel/adxl355_i2c.c +++ b/drivers/iio/accel/adxl355_i2c.c @@ -7,7 +7,6 @@ #include #include -#include #include #include "adxl355.h" diff --git a/drivers/iio/accel/adxl355_spi.c b/drivers/iio/accel/adxl355_spi.c index 347ed62b6582..437be2f1d53c 100644 --- a/drivers/iio/accel/adxl355_spi.c +++ b/drivers/iio/accel/adxl355_spi.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/accel/adxl367.c b/drivers/iio/accel/adxl367.c index 63a0b182824f..8c3de11a10a3 100644 --- a/drivers/iio/accel/adxl367.c +++ b/drivers/iio/accel/adxl367.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/adxl367_i2c.c b/drivers/iio/accel/adxl367_i2c.c index fb50ded68bae..42e747f5d1a1 100644 --- a/drivers/iio/accel/adxl367_i2c.c +++ b/drivers/iio/accel/adxl367_i2c.c @@ -5,7 +5,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/accel/adxl367_spi.c b/drivers/iio/accel/adxl367_spi.c index 3fed56bb9054..785652c7fc92 100644 --- a/drivers/iio/accel/adxl367_spi.c +++ b/drivers/iio/accel/adxl367_spi.c @@ -4,7 +4,6 @@ * Author: Cosmin Tanislav */ -#include #include #include #include diff --git a/drivers/iio/accel/adxl372_i2c.c b/drivers/iio/accel/adxl372_i2c.c index ddb125075778..e06ddb9c9a7b 100644 --- a/drivers/iio/accel/adxl372_i2c.c +++ b/drivers/iio/accel/adxl372_i2c.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/accel/adxl372_spi.c b/drivers/iio/accel/adxl372_spi.c index 1f9c1544e547..25fdb4254372 100644 --- a/drivers/iio/accel/adxl372_spi.c +++ b/drivers/iio/accel/adxl372_spi.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/accel/adxl380_i2c.c b/drivers/iio/accel/adxl380_i2c.c index 367a29298047..2673ddbbdc53 100644 --- a/drivers/iio/accel/adxl380_i2c.c +++ b/drivers/iio/accel/adxl380_i2c.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/accel/adxl380_spi.c b/drivers/iio/accel/adxl380_spi.c index 4ead949b24f1..ee3e6338b53d 100644 --- a/drivers/iio/accel/adxl380_spi.c +++ b/drivers/iio/accel/adxl380_spi.c @@ -5,7 +5,6 @@ * Copyright 2024 Analog Devices Inc. */ -#include #include #include #include diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index e643bc73eefe..62bda8d76691 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -13,7 +13,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/accel/bma220_core.c b/drivers/iio/accel/bma220_core.c index f32d875b994e..269e2b720ddb 100644 --- a/drivers/iio/accel/bma220_core.c +++ b/drivers/iio/accel/bma220_core.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/bma220_i2c.c b/drivers/iio/accel/bma220_i2c.c index b058e97bc6a6..7e850e95cb06 100644 --- a/drivers/iio/accel/bma220_i2c.c +++ b/drivers/iio/accel/bma220_i2c.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/accel/bma220_spi.c b/drivers/iio/accel/bma220_spi.c index 383ee8a135ee..d897aec1c9f2 100644 --- a/drivers/iio/accel/bma220_spi.c +++ b/drivers/iio/accel/bma220_spi.c @@ -5,7 +5,6 @@ * Copyright (c) 2016,2020 Intel Corporation. */ -#include #include #include #include diff --git a/drivers/iio/accel/bma400_i2c.c b/drivers/iio/accel/bma400_i2c.c index 23d394c5a791..a3fb3b81b64c 100644 --- a/drivers/iio/accel/bma400_i2c.c +++ b/drivers/iio/accel/bma400_i2c.c @@ -7,7 +7,6 @@ * I2C address is either 0x14 or 0x15 depending on SDO */ #include -#include #include #include diff --git a/drivers/iio/accel/bma400_spi.c b/drivers/iio/accel/bma400_spi.c index d386f643515b..4b89e313704f 100644 --- a/drivers/iio/accel/bma400_spi.c +++ b/drivers/iio/accel/bma400_spi.c @@ -7,7 +7,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/iio/accel/bmc150-accel-i2c.c b/drivers/iio/accel/bmc150-accel-i2c.c index 3315172742d0..336866aad20c 100644 --- a/drivers/iio/accel/bmc150-accel-i2c.c +++ b/drivers/iio/accel/bmc150-accel-i2c.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/accel/bmc150-accel-spi.c b/drivers/iio/accel/bmc150-accel-spi.c index 26ce50b37716..7d2be6f63538 100644 --- a/drivers/iio/accel/bmc150-accel-spi.c +++ b/drivers/iio/accel/bmc150-accel-spi.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/accel/bmi088-accel-i2c.c b/drivers/iio/accel/bmi088-accel-i2c.c index d9468b1c5aee..aecd66e5685e 100644 --- a/drivers/iio/accel/bmi088-accel-i2c.c +++ b/drivers/iio/accel/bmi088-accel-i2c.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/accel/dmard06.c b/drivers/iio/accel/dmard06.c index 2957bf55d110..82816fa44354 100644 --- a/drivers/iio/accel/dmard06.c +++ b/drivers/iio/accel/dmard06.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/accel/fxls8962af-core.c b/drivers/iio/accel/fxls8962af-core.c index 8763e91c63d2..d0c2a8daef0d 100644 --- a/drivers/iio/accel/fxls8962af-core.c +++ b/drivers/iio/accel/fxls8962af-core.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/fxls8962af-i2c.c b/drivers/iio/accel/fxls8962af-i2c.c index fa46f5aa34f7..e72842b1459e 100644 --- a/drivers/iio/accel/fxls8962af-i2c.c +++ b/drivers/iio/accel/fxls8962af-i2c.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/accel/fxls8962af-spi.c b/drivers/iio/accel/fxls8962af-spi.c index bdafd1f615d9..8936032526a0 100644 --- a/drivers/iio/accel/fxls8962af-spi.c +++ b/drivers/iio/accel/fxls8962af-spi.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index 2bf05ab5235e..737572bb44d9 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 8a082ff034dd..166fb786425f 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 8f3314db82d2..f19626c2f70f 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/kxsd9-spi.c b/drivers/iio/accel/kxsd9-spi.c index cbb6c6412665..31a26baba9f7 100644 --- a/drivers/iio/accel/kxsd9-spi.c +++ b/drivers/iio/accel/kxsd9-spi.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/accel/mma7660.c b/drivers/iio/accel/mma7660.c index 0ecf6c06dcc6..38b4df76cff3 100644 --- a/drivers/iio/accel/mma7660.c +++ b/drivers/iio/accel/mma7660.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 1403b32e2b21..7d683686dd9d 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -20,7 +20,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 020370b0ec07..7d9cbfa01360 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index 90ce86244ee8..ab43b1e0ff04 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/accel/msa311.c b/drivers/iio/accel/msa311.c index 5eace0de3750..e0e73b87cba8 100644 --- a/drivers/iio/accel/msa311.c +++ b/drivers/iio/accel/msa311.c @@ -28,7 +28,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 434971fbfb12..2034fe92bae3 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index 901f2b9f16a2..a9f41cf27ad9 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index eecc7fcdb06e..99522a885d71 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index d8ec0555f42a..e6bf8d0d4ff5 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index ccea1331cafc..d0c53b8ac850 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/88pm886-gpadc.c b/drivers/iio/adc/88pm886-gpadc.c index 4435f3d5e2b8..ff9bc5f06c18 100644 --- a/drivers/iio/adc/88pm886-gpadc.c +++ b/drivers/iio/adc/88pm886-gpadc.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c index fd3d79fca785..c2f6f5f9812c 100644 --- a/drivers/iio/adc/ad4000.c +++ b/drivers/iio/adc/ad4000.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c index 8d2953341b15..0797d64aeaec 100644 --- a/drivers/iio/adc/ad4080.c +++ b/drivers/iio/adc/ad4080.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad4134.c b/drivers/iio/adc/ad4134.c index e42ee328fcbf..cb9d74316f6a 100644 --- a/drivers/iio/adc/ad4134.c +++ b/drivers/iio/adc/ad4134.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad4691.c b/drivers/iio/adc/ad4691.c index 548678adc2a4..f2f7c4c6424a 100644 --- a/drivers/iio/adc/ad4691.c +++ b/drivers/iio/adc/ad4691.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c index 1ad77f2a4580..940b042d743a 100644 --- a/drivers/iio/adc/ad4851.c +++ b/drivers/iio/adc/ad4851.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c index 5c1a8f886bcc..19058d081418 100644 --- a/drivers/iio/adc/ad7124.c +++ b/drivers/iio/adc/ad7124.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c index f76a9e08f39e..9ee65d63c525 100644 --- a/drivers/iio/adc/ad7173.c +++ b/drivers/iio/adc/ad7173.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7191.c b/drivers/iio/adc/ad7191.c index 51ec199fb06f..94b172dce866 100644 --- a/drivers/iio/adc/ad7191.c +++ b/drivers/iio/adc/ad7191.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7192.c b/drivers/iio/adc/ad7192.c index caf4473ad643..2cfad0bda752 100644 --- a/drivers/iio/adc/ad7192.c +++ b/drivers/iio/adc/ad7192.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/ad7280a.c b/drivers/iio/adc/ad7280a.c index 01c2f55a680c..2972e706de92 100644 --- a/drivers/iio/adc/ad7280a.c +++ b/drivers/iio/adc/ad7280a.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index e5ad83d2240a..0ba0fbad4f70 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 7c0538ea15c8..5fa76aec360e 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7405.c b/drivers/iio/adc/ad7405.c index 9adf85a732ce..0996f48d76f1 100644 --- a/drivers/iio/adc/ad7405.c +++ b/drivers/iio/adc/ad7405.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7606_par.c b/drivers/iio/adc/ad7606_par.c index b81e707ab40c..5b137e947f0b 100644 --- a/drivers/iio/adc/ad7606_par.c +++ b/drivers/iio/adc/ad7606_par.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7625.c b/drivers/iio/adc/ad7625.c index f1ee29f35fa8..e73a5c9e7f0b 100644 --- a/drivers/iio/adc/ad7625.c +++ b/drivers/iio/adc/ad7625.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c index 695cc79e78da..003e23d6e242 100644 --- a/drivers/iio/adc/ad7779.c +++ b/drivers/iio/adc/ad7779.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c index ced0a2321ecf..26b9c75bd4d8 100644 --- a/drivers/iio/adc/adi-axi-adc.c +++ b/drivers/iio/adc/adi-axi-adc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index 255970b2e747..e8a5285bb6d4 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c index f9a60e8b05cb..d9016fe1aca9 100644 --- a/drivers/iio/adc/axp20x_adc.c +++ b/drivers/iio/adc/axp20x_adc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/bcm_iproc_adc.c b/drivers/iio/adc/bcm_iproc_adc.c index 6426c9e6ccc9..cf4738b16e62 100644 --- a/drivers/iio/adc/bcm_iproc_adc.c +++ b/drivers/iio/adc/bcm_iproc_adc.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index fa04e0a5f645..a67edf0bddaa 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index f6f72efcc6ed..223e2737c564 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/envelope-detector.c b/drivers/iio/adc/envelope-detector.c index 5b16fe737659..30672e584c10 100644 --- a/drivers/iio/adc/envelope-detector.c +++ b/drivers/iio/adc/envelope-detector.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index e6268f7ac400..dc310ed616a1 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 86c10ea7ded4..b01ba86c2945 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 86d2a70dd3de..17e9badf1d1c 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/imx7d_adc.c b/drivers/iio/adc/imx7d_adc.c index 039c0387da23..e9a509dc11b8 100644 --- a/drivers/iio/adc/imx7d_adc.c +++ b/drivers/iio/adc/imx7d_adc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/imx8qxp-adc.c b/drivers/iio/adc/imx8qxp-adc.c index 6fc50394ad90..d7cc9774359e 100644 --- a/drivers/iio/adc/imx8qxp-adc.c +++ b/drivers/iio/adc/imx8qxp-adc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/imx93_adc.c b/drivers/iio/adc/imx93_adc.c index 787e80db5de3..797adaf371ba 100644 --- a/drivers/iio/adc/imx93_adc.c +++ b/drivers/iio/adc/imx93_adc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 414f69acab7b..71fcdfedb041 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/intel_dc_ti_adc.c b/drivers/iio/adc/intel_dc_ti_adc.c index b5afad713e2d..698a2a3049e3 100644 --- a/drivers/iio/adc/intel_dc_ti_adc.c +++ b/drivers/iio/adc/intel_dc_ti_adc.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index 101c1a0ce591..ff34e597944b 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/lpc18xx_adc.c b/drivers/iio/adc/lpc18xx_adc.c index 7e5d181ff702..2cf2519f55f3 100644 --- a/drivers/iio/adc/lpc18xx_adc.c +++ b/drivers/iio/adc/lpc18xx_adc.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/lpc32xx_adc.c b/drivers/iio/adc/lpc32xx_adc.c index 43a7bc8158b5..0128d003f960 100644 --- a/drivers/iio/adc/lpc32xx_adc.c +++ b/drivers/iio/adc/lpc32xx_adc.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ltc2496.c b/drivers/iio/adc/ltc2496.c index f06dd0b9a858..5b5b6ab28850 100644 --- a/drivers/iio/adc/ltc2496.c +++ b/drivers/iio/adc/ltc2496.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "ltc2497.h" diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c index 8e899d6ffcfa..c1668b5a351e 100644 --- a/drivers/iio/adc/ltc2497.c +++ b/drivers/iio/adc/ltc2497.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 7e736e77d8bb..8b2c7b2a9c8f 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/adc/max11100.c b/drivers/iio/adc/max11100.c index 520e37f75aac..549dea6bf95c 100644 --- a/drivers/iio/adc/max11100.c +++ b/drivers/iio/adc/max11100.c @@ -8,7 +8,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/iio/adc/max1118.c b/drivers/iio/adc/max1118.c index 7d7001e8e3d9..d394e03cc4e8 100644 --- a/drivers/iio/adc/max1118.c +++ b/drivers/iio/adc/max1118.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 4d0b79cfeb27..65a2d92bb112 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/max14001.c b/drivers/iio/adc/max14001.c index 90ad4cb5868d..09017163b191 100644 --- a/drivers/iio/adc/max14001.c +++ b/drivers/iio/adc/max14001.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/max34408.c b/drivers/iio/adc/max34408.c index da847eaed84e..c96dfed6322d 100644 --- a/drivers/iio/adc/max34408.c +++ b/drivers/iio/adc/max34408.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/max77541-adc.c b/drivers/iio/adc/max77541-adc.c index 013da014bccd..6e68cad5b5ce 100644 --- a/drivers/iio/adc/max77541-adc.c +++ b/drivers/iio/adc/max77541-adc.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c index 826566d7a85e..45cea84c5d4a 100644 --- a/drivers/iio/adc/max9611.c +++ b/drivers/iio/adc/max9611.c @@ -22,7 +22,6 @@ #include #include #include -#include #include /* max9611 register addresses */ diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 57cff3772ebe..686c519aa3d2 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/mcp3422.c b/drivers/iio/adc/mcp3422.c index f49cde672958..36ba00edf301 100644 --- a/drivers/iio/adc/mcp3422.c +++ b/drivers/iio/adc/mcp3422.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c index ddc3721f3f68..5bf74b49bdb5 100644 --- a/drivers/iio/adc/mcp3911.c +++ b/drivers/iio/adc/mcp3911.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c index 5a1d516f8dad..c03f89ddbd13 100644 --- a/drivers/iio/adc/mp2629_adc.c +++ b/drivers/iio/adc/mp2629_adc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c index 1d9724ef0983..88b0e26309e5 100644 --- a/drivers/iio/adc/mt6359-auxadc.c +++ b/drivers/iio/adc/mt6359-auxadc.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c index e0e4df418612..e59b13e88aa2 100644 --- a/drivers/iio/adc/mt6360-adc.c +++ b/drivers/iio/adc/mt6360-adc.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/mt6370-adc.c b/drivers/iio/adc/mt6370-adc.c index 7c71fe5e8d31..c250385f9d34 100644 --- a/drivers/iio/adc/mt6370-adc.c +++ b/drivers/iio/adc/mt6370-adc.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/mt6577_auxadc.c b/drivers/iio/adc/mt6577_auxadc.c index fe9e3ece3fda..ecbae90ac2ed 100644 --- a/drivers/iio/adc/mt6577_auxadc.c +++ b/drivers/iio/adc/mt6577_auxadc.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/nau7802.c b/drivers/iio/adc/nau7802.c index 836c9b49c721..dccf11fbf88a 100644 --- a/drivers/iio/adc/nau7802.c +++ b/drivers/iio/adc/nau7802.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/nct7201.c b/drivers/iio/adc/nct7201.c index d87824e5490f..bea88a9b9440 100644 --- a/drivers/iio/adc/nct7201.c +++ b/drivers/iio/adc/nct7201.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/npcm_adc.c b/drivers/iio/adc/npcm_adc.c index 61c8b825bda1..a25c15b38759 100644 --- a/drivers/iio/adc/npcm_adc.c +++ b/drivers/iio/adc/npcm_adc.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c index 15c7432808f4..35b81331fdee 100644 --- a/drivers/iio/adc/nxp-sar-adc.c +++ b/drivers/iio/adc/nxp-sar-adc.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/qcom-pm8xxx-xoadc.c b/drivers/iio/adc/qcom-pm8xxx-xoadc.c index 4a1a0cfb4699..3cdf90c4444b 100644 --- a/drivers/iio/adc/qcom-pm8xxx-xoadc.c +++ b/drivers/iio/adc/qcom-pm8xxx-xoadc.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/qcom-spmi-adc5-gen3.c b/drivers/iio/adc/qcom-spmi-adc5-gen3.c index 48c793b18d11..c56b650fd8c0 100644 --- a/drivers/iio/adc/qcom-spmi-adc5-gen3.c +++ b/drivers/iio/adc/qcom-spmi-adc5-gen3.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index af3c2f659f5e..83ecd3adf65f 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c index 8e75665204d1..1682c6faf62c 100644 --- a/drivers/iio/adc/qcom-spmi-rradc.c +++ b/drivers/iio/adc/qcom-spmi-rradc.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index 00a7f0982025..d7a2df3c810e 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/rohm-bd79112.c b/drivers/iio/adc/rohm-bd79112.c index 7420aa6627d5..c4b0bec80794 100644 --- a/drivers/iio/adc/rohm-bd79112.c +++ b/drivers/iio/adc/rohm-bd79112.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/rohm-bd79124.c b/drivers/iio/adc/rohm-bd79124.c index 864f3b1366b5..ed5427288961 100644 --- a/drivers/iio/adc/rohm-bd79124.c +++ b/drivers/iio/adc/rohm-bd79124.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c index e2b1da13c0d3..ba525a3c5cc2 100644 --- a/drivers/iio/adc/rtq6056.c +++ b/drivers/iio/adc/rtq6056.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c index 1010e0511b3e..408fbf8c29cc 100644 --- a/drivers/iio/adc/rzg2l_adc.c +++ b/drivers/iio/adc/rzg2l_adc.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/rzn1-adc.c b/drivers/iio/adc/rzn1-adc.c index 93b0feef8ea0..f921cd49b789 100644 --- a/drivers/iio/adc/rzn1-adc.c +++ b/drivers/iio/adc/rzn1-adc.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/rzt2h_adc.c b/drivers/iio/adc/rzt2h_adc.c index 33ce5cc44ff4..4e0eb02d3d14 100644 --- a/drivers/iio/adc/rzt2h_adc.c +++ b/drivers/iio/adc/rzt2h_adc.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c index 218117c45ec8..def44d8831dc 100644 --- a/drivers/iio/adc/sd_adc_modulator.c +++ b/drivers/iio/adc/sd_adc_modulator.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/sophgo-cv1800b-adc.c b/drivers/iio/adc/sophgo-cv1800b-adc.c index 0951deb7b111..bdc3e1326a9a 100644 --- a/drivers/iio/adc/sophgo-cv1800b-adc.c +++ b/drivers/iio/adc/sophgo-cv1800b-adc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/spear_adc.c b/drivers/iio/adc/spear_adc.c index 4be722406bb5..bdb3ca8f229a 100644 --- a/drivers/iio/adc/spear_adc.c +++ b/drivers/iio/adc/spear_adc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 5c5170b19b56..5c6c06b269be 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/sun20i-gpadc-iio.c b/drivers/iio/adc/sun20i-gpadc-iio.c index 81fc4610e15e..baa7661db13b 100644 --- a/drivers/iio/adc/sun20i-gpadc-iio.c +++ b/drivers/iio/adc/sun20i-gpadc-iio.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c index 33f82bdfeb94..e33a2f4bf66c 100644 --- a/drivers/iio/adc/ti-adc081c.c +++ b/drivers/iio/adc/ti-adc081c.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/ti-adc0832.c b/drivers/iio/adc/ti-adc0832.c index cfcdafbe284b..63d712d5d111 100644 --- a/drivers/iio/adc/ti-adc0832.c +++ b/drivers/iio/adc/ti-adc0832.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-adc084s021.c b/drivers/iio/adc/ti-adc084s021.c index a100f770fa1c..51596b500a90 100644 --- a/drivers/iio/adc/ti-adc084s021.c +++ b/drivers/iio/adc/ti-adc084s021.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-adc108s102.c b/drivers/iio/adc/ti-adc108s102.c index 7d615e2bbf39..d1f61b440959 100644 --- a/drivers/iio/adc/ti-adc108s102.c +++ b/drivers/iio/adc/ti-adc108s102.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 4ae65793ad9b..2cb68582ee6a 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index be1cc2e77862..08aa32bd5e4b 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c index 0780abd0d0db..d6624c71a374 100644 --- a/drivers/iio/adc/ti-ads1018.c +++ b/drivers/iio/adc/ti-ads1018.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-ads124s08.c b/drivers/iio/adc/ti-ads124s08.c index 8ea1269f74db..522b43118af6 100644 --- a/drivers/iio/adc/ti-ads124s08.c +++ b/drivers/iio/adc/ti-ads124s08.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/ti-ads131m02.c b/drivers/iio/adc/ti-ads131m02.c index 07d63bf62c5f..36203ce37c89 100644 --- a/drivers/iio/adc/ti-ads131m02.c +++ b/drivers/iio/adc/ti-ads131m02.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index ebd2826a7ff6..ba5e240aa41a 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/adc/ti-tlc4541.c b/drivers/iio/adc/ti-tlc4541.c index f67945c62c99..94bbf5afe30e 100644 --- a/drivers/iio/adc/ti-tlc4541.c +++ b/drivers/iio/adc/ti-tlc4541.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index f0274cd74973..0ee7e16b5e24 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/twl6030-gpadc.c b/drivers/iio/adc/twl6030-gpadc.c index 7810d6b2b668..31b1c01baa27 100644 --- a/drivers/iio/adc/twl6030-gpadc.c +++ b/drivers/iio/adc/twl6030-gpadc.c @@ -16,7 +16,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index d7182ed0d2a7..bcbeb482e714 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -5,7 +5,6 @@ * Copyright 2013 Freescale Semiconductor, Inc. */ -#include #include #include #include diff --git a/drivers/iio/adc/xilinx-ams.c b/drivers/iio/adc/xilinx-ams.c index d38c4401dfce..158e6133abf5 100644 --- a/drivers/iio/adc/xilinx-ams.c +++ b/drivers/iio/adc/xilinx-ams.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 3980dfacbcd7..cab66bb8cc1c 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/addac/ad74413r.c b/drivers/iio/addac/ad74413r.c index fe930ce5ee30..43bd2079cf6d 100644 --- a/drivers/iio/addac/ad74413r.c +++ b/drivers/iio/addac/ad74413r.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index ecaf59278c6f..654a3a50eb4f 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c index bbf41a1fb3a1..affc9c9d8488 100644 --- a/drivers/iio/amplifiers/ad8366.c +++ b/drivers/iio/amplifiers/ad8366.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/amplifiers/adl8113.c b/drivers/iio/amplifiers/adl8113.c index b8a431b6616b..1f1cfca980b4 100644 --- a/drivers/iio/amplifiers/adl8113.c +++ b/drivers/iio/amplifiers/adl8113.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/amplifiers/hmc425a.c b/drivers/iio/amplifiers/hmc425a.c index 4dbf894c7e3b..85bfc8dcc5fb 100644 --- a/drivers/iio/amplifiers/hmc425a.c +++ b/drivers/iio/amplifiers/hmc425a.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/cdc/ad7150.c b/drivers/iio/cdc/ad7150.c index cb9fff3bd67f..2f35c6d2f9ce 100644 --- a/drivers/iio/cdc/ad7150.c +++ b/drivers/iio/cdc/ad7150.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/chemical/ams-iaq-core.c b/drivers/iio/chemical/ams-iaq-core.c index 7aa7841c530e..7af515110b89 100644 --- a/drivers/iio/chemical/ams-iaq-core.c +++ b/drivers/iio/chemical/ams-iaq-core.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/chemical/atlas-ezo-sensor.c b/drivers/iio/chemical/atlas-ezo-sensor.c index 05da3b8a92ab..298b2fe48a19 100644 --- a/drivers/iio/chemical/atlas-ezo-sensor.c +++ b/drivers/iio/chemical/atlas-ezo-sensor.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 0e2edcff63f9..1e8adbe1790d 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/bme680_spi.c b/drivers/iio/chemical/bme680_spi.c index aa97645ba539..785200a6fd65 100644 --- a/drivers/iio/chemical/bme680_spi.c +++ b/drivers/iio/chemical/bme680_spi.c @@ -4,7 +4,6 @@ * * Copyright (C) 2018 Himanshu Jha */ -#include #include #include #include diff --git a/drivers/iio/chemical/mhz19b.c b/drivers/iio/chemical/mhz19b.c index 9d4cf432919e..a793620e95b7 100644 --- a/drivers/iio/chemical/mhz19b.c +++ b/drivers/iio/chemical/mhz19b.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/pms7003.c b/drivers/iio/chemical/pms7003.c index 656d4a12c58f..c50edb24af89 100644 --- a/drivers/iio/chemical/pms7003.c +++ b/drivers/iio/chemical/pms7003.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/scd30_i2c.c b/drivers/iio/chemical/scd30_i2c.c index 9e841f565149..abceccdddc71 100644 --- a/drivers/iio/chemical/scd30_i2c.c +++ b/drivers/iio/chemical/scd30_i2c.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/scd30_serial.c b/drivers/iio/chemical/scd30_serial.c index e8b453aae859..7fefdadbfa0a 100644 --- a/drivers/iio/chemical/scd30_serial.c +++ b/drivers/iio/chemical/scd30_serial.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index 8b88be85602c..f10bbebc29e4 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/sps30_i2c.c b/drivers/iio/chemical/sps30_i2c.c index 61781aaabd85..90f1adb8c89f 100644 --- a/drivers/iio/chemical/sps30_i2c.c +++ b/drivers/iio/chemical/sps30_i2c.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/chemical/sps30_serial.c b/drivers/iio/chemical/sps30_serial.c index a5e6bc08d5fd..80eab9b2e4bf 100644 --- a/drivers/iio/chemical/sps30_serial.c +++ b/drivers/iio/chemical/sps30_serial.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/sunrise_co2.c b/drivers/iio/chemical/sunrise_co2.c index 158be9d798d2..dae8a7025e05 100644 --- a/drivers/iio/chemical/sunrise_co2.c +++ b/drivers/iio/chemical/sunrise_co2.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 4deacf10b6ef..2e10a6b17047 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c index 2d3d148b4206..8f5bf40a0596 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_lid_angle.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c index 651632ccfe0d..b971f8b646be 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c index 51730dae5871..828fcfe1d4f1 100644 --- a/drivers/iio/common/ssp_sensors/ssp_dev.c +++ b/drivers/iio/common/ssp_sensors/ssp_dev.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/dac/ad3530r.c b/drivers/iio/dac/ad3530r.c index d9db3226ecd6..4e911bfb6fc5 100644 --- a/drivers/iio/dac/ad3530r.c +++ b/drivers/iio/dac/ad3530r.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ad3552r-hs.c b/drivers/iio/dac/ad3552r-hs.c index 6bc64f53bce9..02a124ac4855 100644 --- a/drivers/iio/dac/ad3552r-hs.c +++ b/drivers/iio/dac/ad3552r-hs.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ad5446-i2c.c b/drivers/iio/dac/ad5446-i2c.c index 2d4c8908d91e..9797fc3e57a9 100644 --- a/drivers/iio/dac/ad5446-i2c.c +++ b/drivers/iio/dac/ad5446-i2c.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include diff --git a/drivers/iio/dac/ad5446-spi.c b/drivers/iio/dac/ad5446-spi.c index e29d77f21482..54bd0e113f40 100644 --- a/drivers/iio/dac/ad5446-spi.c +++ b/drivers/iio/dac/ad5446-spi.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include diff --git a/drivers/iio/dac/ad5592r.c b/drivers/iio/dac/ad5592r.c index 92d1b629b85d..88197bc6a70b 100644 --- a/drivers/iio/dac/ad5592r.c +++ b/drivers/iio/dac/ad5592r.c @@ -10,7 +10,6 @@ #include #include -#include #include #define AD5592R_GPIO_READBACK_EN BIT(10) diff --git a/drivers/iio/dac/ad5593r.c b/drivers/iio/dac/ad5593r.c index 9a8525c61173..3e4215f0ca7e 100644 --- a/drivers/iio/dac/ad5593r.c +++ b/drivers/iio/dac/ad5593r.c @@ -11,7 +11,6 @@ #include #include #include -#include #include diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 6b6ef1d7071f..8abfaf8f0c46 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index 279309329b64..d49946adbde3 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/dac/ad5706r.c b/drivers/iio/dac/ad5706r.c index f7872e92dc01..e4e48ca7ad34 100644 --- a/drivers/iio/dac/ad5706r.c +++ b/drivers/iio/dac/ad5706r.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ad5758.c b/drivers/iio/dac/ad5758.c index 8e6fb46cce4d..bb30842e7080 100644 --- a/drivers/iio/dac/ad5758.c +++ b/drivers/iio/dac/ad5758.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ad7293.c b/drivers/iio/dac/ad7293.c index df6f126abf05..03acf7c114b0 100644 --- a/drivers/iio/dac/ad7293.c +++ b/drivers/iio/dac/ad7293.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index 1c2960fa9743..6451fc586a67 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ad8460.c b/drivers/iio/dac/ad8460.c index 6e45686902dd..ddec62b6e57b 100644 --- a/drivers/iio/dac/ad8460.c +++ b/drivers/iio/dac/ad8460.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ad9739a.c b/drivers/iio/dac/ad9739a.c index d77b46d83bd4..ccd6a3b1e891 100644 --- a/drivers/iio/dac/ad9739a.c +++ b/drivers/iio/dac/ad9739a.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/adi-axi-dac.c b/drivers/iio/dac/adi-axi-dac.c index 451fad34e7ee..f4f3bc67c68e 100644 --- a/drivers/iio/dac/adi-axi-dac.c +++ b/drivers/iio/dac/adi-axi-dac.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/dpot-dac.c b/drivers/iio/dac/dpot-dac.c index d1b8441051ae..cf6d94e7af84 100644 --- a/drivers/iio/dac/dpot-dac.c +++ b/drivers/iio/dac/dpot-dac.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/dac/lpc18xx_dac.c b/drivers/iio/dac/lpc18xx_dac.c index aa1c73f8429d..43fb9e5a2c56 100644 --- a/drivers/iio/dac/lpc18xx_dac.c +++ b/drivers/iio/dac/lpc18xx_dac.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ltc2664.c b/drivers/iio/dac/ltc2664.c index 616806615d3d..c48b9efc8280 100644 --- a/drivers/iio/dac/ltc2664.c +++ b/drivers/iio/dac/ltc2664.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ltc2688.c b/drivers/iio/dac/ltc2688.c index 02f408229681..a575ef8371dc 100644 --- a/drivers/iio/dac/ltc2688.c +++ b/drivers/iio/dac/ltc2688.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/max22007.c b/drivers/iio/dac/max22007.c index 182ac7155a89..d747901df5a3 100644 --- a/drivers/iio/dac/max22007.c +++ b/drivers/iio/dac/max22007.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/max5522.c b/drivers/iio/dac/max5522.c index b52a9cc1da79..1459ba132df6 100644 --- a/drivers/iio/dac/max5522.c +++ b/drivers/iio/dac/max5522.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 2d6bcfd5deaa..3fa7acc69aeb 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/dac/mcp4728.c b/drivers/iio/dac/mcp4728.c index 64bd9490fc19..1fe184d49fc5 100644 --- a/drivers/iio/dac/mcp4728.c +++ b/drivers/iio/dac/mcp4728.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c index 217f78e44af1..5c0f3064df7a 100644 --- a/drivers/iio/dac/mcp47feb02.c +++ b/drivers/iio/dac/mcp47feb02.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/mcp4821.c b/drivers/iio/dac/mcp4821.c index 18b5934fb8a2..d2e7c930c848 100644 --- a/drivers/iio/dac/mcp4821.c +++ b/drivers/iio/dac/mcp4821.c @@ -16,7 +16,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index 8ef702917060..b5795c14f0fe 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index b860e18d52a1..99438f6d4700 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/dac/ti-dac082s085.c b/drivers/iio/dac/ti-dac082s085.c index 715870c8a9c4..6e62c1f302c8 100644 --- a/drivers/iio/dac/ti-dac082s085.c +++ b/drivers/iio/dac/ti-dac082s085.c @@ -14,7 +14,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/dac/ti-dac5571.c b/drivers/iio/dac/ti-dac5571.c index b9efd704e996..78fd5fa42db6 100644 --- a/drivers/iio/dac/ti-dac5571.c +++ b/drivers/iio/dac/ti-dac5571.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/dac/vf610_dac.c b/drivers/iio/dac/vf610_dac.c index 93639599b2b9..3aa22fecd308 100644 --- a/drivers/iio/dac/vf610_dac.c +++ b/drivers/iio/dac/vf610_dac.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/filter/admv8818.c b/drivers/iio/filter/admv8818.c index a4984b867248..8bcd298e1f3d 100644 --- a/drivers/iio/filter/admv8818.c +++ b/drivers/iio/filter/admv8818.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c index 6bbb6a8dd9d0..639cac522b44 100644 --- a/drivers/iio/frequency/adf4350.c +++ b/drivers/iio/frequency/adf4350.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/frequency/admfm2000.c b/drivers/iio/frequency/admfm2000.c index b2263b9afeda..0405b53c5851 100644 --- a/drivers/iio/frequency/admfm2000.c +++ b/drivers/iio/frequency/admfm2000.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/frequency/admv1013.c b/drivers/iio/frequency/admv1013.c index b852378b3f68..b823adfb0f70 100644 --- a/drivers/iio/frequency/admv1013.c +++ b/drivers/iio/frequency/admv1013.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/frequency/admv1014.c b/drivers/iio/frequency/admv1014.c index 25e8cd8135ad..5d36ac4bb666 100644 --- a/drivers/iio/frequency/admv1014.c +++ b/drivers/iio/frequency/admv1014.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/frequency/adrf6780.c b/drivers/iio/frequency/adrf6780.c index 9911b5273b22..c2dc06f05c21 100644 --- a/drivers/iio/frequency/adrf6780.c +++ b/drivers/iio/frequency/adrf6780.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 028e5e29c6a1..be3cfbd286aa 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -3,7 +3,6 @@ #include #include #include -#include #include "bmg160.h" diff --git a/drivers/iio/gyro/fxas21002c_i2c.c b/drivers/iio/gyro/fxas21002c_i2c.c index d537e91caaaf..634f9019aa96 100644 --- a/drivers/iio/gyro/fxas21002c_i2c.c +++ b/drivers/iio/gyro/fxas21002c_i2c.c @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/gyro/fxas21002c_spi.c b/drivers/iio/gyro/fxas21002c_spi.c index d62efe50b697..bd5b8678da13 100644 --- a/drivers/iio/gyro/fxas21002c_spi.c +++ b/drivers/iio/gyro/fxas21002c_spi.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index e48c25c87b6d..adc52a5267f7 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index b07cb39051b3..a587e9023ceb 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index f645da157372..adfbbc0d37dc 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/health/max30102.c b/drivers/iio/health/max30102.c index c830eaf286f7..0eeaa378b10d 100644 --- a/drivers/iio/health/max30102.c +++ b/drivers/iio/health/max30102.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 980cb946bbf7..7690df97fd6c 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/humidity/ens210.c b/drivers/iio/humidity/ens210.c index 49543fc389bf..81276195152b 100644 --- a/drivers/iio/humidity/ens210.c +++ b/drivers/iio/humidity/ens210.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/humidity/hdc100x.c b/drivers/iio/humidity/hdc100x.c index 87194802cc4f..bc452cc8fbcf 100644 --- a/drivers/iio/humidity/hdc100x.c +++ b/drivers/iio/humidity/hdc100x.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/humidity/hid-sensor-humidity.c b/drivers/iio/humidity/hid-sensor-humidity.c index be2338d5f407..5267a14d73ec 100644 --- a/drivers/iio/humidity/hid-sensor-humidity.c +++ b/drivers/iio/humidity/hid-sensor-humidity.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "hid-sensor-trigger.h" diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index e823d37384d7..40276abc5d2e 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/humidity/htu21.c b/drivers/iio/humidity/htu21.c index 9ba7507f105e..a9dbf08b4f1a 100644 --- a/drivers/iio/humidity/htu21.c +++ b/drivers/iio/humidity/htu21.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c index 9fb1e3ede3ff..e51dd7151e4a 100644 --- a/drivers/iio/humidity/si7020.c +++ b/drivers/iio/humidity/si7020.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/adis16475.c b/drivers/iio/imu/adis16475.c index ab39bea1e729..17335386d8e3 100644 --- a/drivers/iio/imu/adis16475.c +++ b/drivers/iio/imu/adis16475.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 543d5c4bfb11..e009f3824768 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/adis16550.c b/drivers/iio/imu/adis16550.c index 75679612052f..1e435d60cd6d 100644 --- a/drivers/iio/imu/adis16550.c +++ b/drivers/iio/imu/adis16550.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 29f3c4acb123..3f3ee044a9cf 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -9,7 +9,6 @@ * - 0x69 if SDO is pulled to VDDIO */ #include -#include #include #include #include diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index 3581bd788483..2f0a578ee40f 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -5,7 +5,6 @@ * Copyright (c) 2016, Intel Corporation. * */ -#include #include #include #include diff --git a/drivers/iio/imu/bmi270/bmi270_i2c.c b/drivers/iio/imu/bmi270/bmi270_i2c.c index 1e6839f9669e..7c035e82e6e9 100644 --- a/drivers/iio/imu/bmi270/bmi270_i2c.c +++ b/drivers/iio/imu/bmi270/bmi270_i2c.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/imu/bmi270/bmi270_spi.c b/drivers/iio/imu/bmi270/bmi270_spi.c index 80c9fa1d685a..dc7fa01421bc 100644 --- a/drivers/iio/imu/bmi270/bmi270_spi.c +++ b/drivers/iio/imu/bmi270/bmi270_spi.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) #include -#include #include #include #include diff --git a/drivers/iio/imu/bmi323/bmi323_i2c.c b/drivers/iio/imu/bmi323/bmi323_i2c.c index 328733ddeed7..e835b91ea6b4 100644 --- a/drivers/iio/imu/bmi323/bmi323_i2c.c +++ b/drivers/iio/imu/bmi323/bmi323_i2c.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/imu/bmi323/bmi323_spi.c b/drivers/iio/imu/bmi323/bmi323_spi.c index fd56ab620750..92f1c4bcc192 100644 --- a/drivers/iio/imu/bmi323/bmi323_spi.c +++ b/drivers/iio/imu/bmi323/bmi323_spi.c @@ -5,7 +5,6 @@ * Copyright (C) 2023, Jagath Jog J */ -#include #include #include #include diff --git a/drivers/iio/imu/bno055/bno055_i2c.c b/drivers/iio/imu/bno055/bno055_i2c.c index 000bc9392480..7117ec682365 100644 --- a/drivers/iio/imu/bno055/bno055_i2c.c +++ b/drivers/iio/imu/bno055/bno055_i2c.c @@ -8,7 +8,6 @@ */ #include -#include #include #include diff --git a/drivers/iio/imu/bno055/bno055_ser_core.c b/drivers/iio/imu/bno055/bno055_ser_core.c index 733f9112de06..01f05feaae0a 100644 --- a/drivers/iio/imu/bno055/bno055_ser_core.c +++ b/drivers/iio/imu/bno055/bno055_ser_core.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c index c81e48c9d8e2..ba47e9260928 100644 --- a/drivers/iio/imu/fxos8700_i2c.c +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -12,7 +12,6 @@ */ #include #include -#include #include #include "fxos8700.h" diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c index 6b0dc7a776b9..3edf90220bfa 100644 --- a/drivers/iio/imu/fxos8700_spi.c +++ b/drivers/iio/imu/fxos8700_spi.c @@ -3,7 +3,6 @@ * FXOS8700 - NXP IMU, SPI bits */ #include -#include #include #include diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c index 99d37ac53bbe..1013aff4f0ab 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_i2c.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c index 13e2e7d38638..57e3c448dca1 100644 --- a/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c +++ b/drivers/iio/imu/inv_icm42600/inv_icm42600_spi.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c index 26fba538a3cf..81ba1b60f04b 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i2c.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include "inv_icm45600.h" diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c index 9247eae9b3e2..8fb2e519bfc8 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_i3c.c @@ -2,7 +2,6 @@ /* Copyright (C) 2025 InvenSense, Inc. */ #include -#include #include #include diff --git a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c index 6288113a6d7c..450a0f2abaaa 100644 --- a/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c +++ b/drivers/iio/imu/inv_icm45600/inv_icm45600_spi.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 4868e1576cee..9ef6ab74af8b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 1f4c62142b60..b8204eb0b4c6 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -2,7 +2,6 @@ /* * Copyright (C) 2015 Intel Corporation Inc. */ -#include #include #include #include diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index b8a8297b39af..c288437d53ea 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/imu/smi330/smi330_i2c.c b/drivers/iio/imu/smi330/smi330_i2c.c index e5f1825beb71..eb9413e22e14 100644 --- a/drivers/iio/imu/smi330/smi330_i2c.c +++ b/drivers/iio/imu/smi330/smi330_i2c.c @@ -3,7 +3,6 @@ * Copyright (c) 2025 Robert Bosch GmbH. */ #include -#include #include #include diff --git a/drivers/iio/imu/smi330/smi330_spi.c b/drivers/iio/imu/smi330/smi330_spi.c index a6044e02b451..78c2bfb15cce 100644 --- a/drivers/iio/imu/smi330/smi330_spi.c +++ b/drivers/iio/imu/smi330/smi330_spi.c @@ -2,7 +2,6 @@ /* * Copyright (c) 2025 Robert Bosch GmbH. */ -#include #include #include #include diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c index cb5c5d7e1f3d..cd59edcf6d71 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i3c.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c index f71ae7a59a22..6581d14e2bcf 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_i2c.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c index acea8a0757d7..8c5d8535e54c 100644 --- a/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c +++ b/drivers/iio/imu/st_lsm9ds0/st_lsm9ds0_spi.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/light/al3000a.c b/drivers/iio/light/al3000a.c index d4e6fedf3d9e..957ec42333ef 100644 --- a/drivers/iio/light/al3000a.c +++ b/drivers/iio/light/al3000a.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/al3010.c b/drivers/iio/light/al3010.c index d603b4a6b8e8..62a77acfd075 100644 --- a/drivers/iio/light/al3010.c +++ b/drivers/iio/light/al3010.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/light/al3320a.c b/drivers/iio/light/al3320a.c index 4ba0ecf355d5..8bb7f7e878c2 100644 --- a/drivers/iio/light/al3320a.c +++ b/drivers/iio/light/al3320a.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/light/apds9999.c b/drivers/iio/light/apds9999.c index 7a0df5252078..43fa9992c9c2 100644 --- a/drivers/iio/light/apds9999.c +++ b/drivers/iio/light/apds9999.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/bh1780.c b/drivers/iio/light/bh1780.c index ead98fb82af9..5447b990ffb7 100644 --- a/drivers/iio/light/bh1780.c +++ b/drivers/iio/light/bh1780.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index bb90f738312a..2590fc8fd154 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index fec233d06602..5f25452633f2 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/light/cm3605.c b/drivers/iio/light/cm3605.c index 0c17378e27d1..98c84f33db60 100644 --- a/drivers/iio/light/cm3605.c +++ b/drivers/iio/light/cm3605.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/light/cros_ec_light_prox.c b/drivers/iio/light/cros_ec_light_prox.c index d09dea9c0782..7ab565b1fb9f 100644 --- a/drivers/iio/light/cros_ec_light_prox.c +++ b/drivers/iio/light/cros_ec_light_prox.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index c218bb3519df..63591b7ecb89 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index d72e260b8266..6bf1bc9a38fe 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c index edc9274a2c07..95bf2bfd86ee 100644 --- a/drivers/iio/light/hid-sensor-prox.c +++ b/drivers/iio/light/hid-sensor-prox.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/isl29018.c b/drivers/iio/light/isl29018.c index 8a39afaa2a37..759cb71ed1c5 100644 --- a/drivers/iio/light/isl29018.c +++ b/drivers/iio/light/isl29018.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index cc0a7c4a33dd..038ee49723ae 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 15dd82ecf745..7d045be78c6d 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/light/ltrf216a.c b/drivers/iio/light/ltrf216a.c index aad96fc91565..3f34ddc911b4 100644 --- a/drivers/iio/light/ltrf216a.c +++ b/drivers/iio/light/ltrf216a.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index 6594054c40c7..8c344f1b3fe2 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c index 0743e16f2a8f..c5bd7fa23fb7 100644 --- a/drivers/iio/light/opt3001.c +++ b/drivers/iio/light/opt3001.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 2ac06dad6d19..f961973892f2 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/light/si1133.c b/drivers/iio/light/si1133.c index 2812a2be99dd..22073ded8081 100644 --- a/drivers/iio/light/si1133.c +++ b/drivers/iio/light/si1133.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index ed8cac5b8766..d6b5ba139dd4 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index a5aad74ce73e..c4c15093e9e5 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 8380df7ffa98..e7ce6f32592b 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 7e277bc6a8b1..45f3513d931e 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c index d335e5e551f1..ab518311fd79 100644 --- a/drivers/iio/light/us5182d.c +++ b/drivers/iio/light/us5182d.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/light/veml3328.c b/drivers/iio/light/veml3328.c index 9309deb5bf19..7ff1753925c4 100644 --- a/drivers/iio/light/veml3328.c +++ b/drivers/iio/light/veml3328.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/veml6046x00.c b/drivers/iio/light/veml6046x00.c index f23d63291f73..b40b70679640 100644 --- a/drivers/iio/light/veml6046x00.c +++ b/drivers/iio/light/veml6046x00.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/light/vl6180.c b/drivers/iio/light/vl6180.c index 6cb965418dba..4f270f405b21 100644 --- a/drivers/iio/light/vl6180.c +++ b/drivers/iio/light/vl6180.c @@ -16,7 +16,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 18dc36945a97..c7fdb7c2f543 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -12,7 +12,6 @@ * Author: Linus Walleij */ #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index d045ea091205..8b0c07f82602 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/bmc150_magn_i2c.c b/drivers/iio/magnetometer/bmc150_magn_i2c.c index 7d3cca8cedbe..28f2bee217d1 100644 --- a/drivers/iio/magnetometer/bmc150_magn_i2c.c +++ b/drivers/iio/magnetometer/bmc150_magn_i2c.c @@ -8,7 +8,6 @@ * Copyright (c) 2016, Intel Corporation. */ #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index 896b1d280731..8af8d3528c43 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -8,7 +8,6 @@ * Copyright (c) 2016, Intel Corporation. */ #include -#include #include #include diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 23884825eb00..d8b8bcc865c3 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index bad36c8dd598..6f40cba4b1ba 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/mmc5633.c b/drivers/iio/magnetometer/mmc5633.c index f82cb68f9c57..f4dae7ba1335 100644 --- a/drivers/iio/magnetometer/mmc5633.c +++ b/drivers/iio/magnetometer/mmc5633.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/mmc5983.c b/drivers/iio/magnetometer/mmc5983.c index a67b13393b6b..03f46e8c1611 100644 --- a/drivers/iio/magnetometer/mmc5983.c +++ b/drivers/iio/magnetometer/mmc5983.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/si7210.c b/drivers/iio/magnetometer/si7210.c index 5b3fc3030703..e9670d671a28 100644 --- a/drivers/iio/magnetometer/si7210.c +++ b/drivers/iio/magnetometer/si7210.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 26d1edd1e779..de66016811db 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 68816362bb95..69693e836ad7 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/magnetometer/tlv493d.c b/drivers/iio/magnetometer/tlv493d.c index c8eb136cea6f..03415cc2c9b3 100644 --- a/drivers/iio/magnetometer/tlv493d.c +++ b/drivers/iio/magnetometer/tlv493d.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/magnetometer/yamaha-yas530.c b/drivers/iio/magnetometer/yamaha-yas530.c index a89e9672530c..f9afe9a59464 100644 --- a/drivers/iio/magnetometer/yamaha-yas530.c +++ b/drivers/iio/magnetometer/yamaha-yas530.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/multiplexer/iio-mux.c b/drivers/iio/multiplexer/iio-mux.c index b742ca9a99d1..4421dafcf94e 100644 --- a/drivers/iio/multiplexer/iio-mux.c +++ b/drivers/iio/multiplexer/iio-mux.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c index 4e23a598a3fb..ea60611192f3 100644 --- a/drivers/iio/orientation/hid-sensor-incl-3d.c +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index 4a11e4555099..52d39c104560 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/position/hid-sensor-custom-intel-hinge.c b/drivers/iio/position/hid-sensor-custom-intel-hinge.c index a26d391661fd..bffa8fe4fe44 100644 --- a/drivers/iio/position/hid-sensor-custom-intel-hinge.c +++ b/drivers/iio/position/hid-sensor-custom-intel-hinge.c @@ -8,7 +8,6 @@ #include #include #include -#include #include "../common/hid-sensors/hid-sensor-trigger.h" diff --git a/drivers/iio/potentiometer/ad5272.c b/drivers/iio/potentiometer/ad5272.c index ac342127d59e..35fe1575e972 100644 --- a/drivers/iio/potentiometer/ad5272.c +++ b/drivers/iio/potentiometer/ad5272.c @@ -15,7 +15,6 @@ #include #include #include -#include #define AD5272_RDAC_WR 1 #define AD5272_RDAC_RD 2 diff --git a/drivers/iio/potentiometer/ds1803.c b/drivers/iio/potentiometer/ds1803.c index 42394343b5a9..5046119b78b0 100644 --- a/drivers/iio/potentiometer/ds1803.c +++ b/drivers/iio/potentiometer/ds1803.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #define DS1803_WIPER_0 0xA9 diff --git a/drivers/iio/potentiometer/max5432.c b/drivers/iio/potentiometer/max5432.c index 26390be79d02..f6d3ec04fdcf 100644 --- a/drivers/iio/potentiometer/max5432.c +++ b/drivers/iio/potentiometer/max5432.c @@ -11,7 +11,6 @@ #include #include #include -#include #include /* All chip variants have 32 wiper positions. */ diff --git a/drivers/iio/potentiometer/max5481.c b/drivers/iio/potentiometer/max5481.c index b40e5ac218d7..ddf54a1df976 100644 --- a/drivers/iio/potentiometer/max5481.c +++ b/drivers/iio/potentiometer/max5481.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/potentiometer/max5487.c b/drivers/iio/potentiometer/max5487.c index 3b11b991940b..9541695af474 100644 --- a/drivers/iio/potentiometer/max5487.c +++ b/drivers/iio/potentiometer/max5487.c @@ -5,7 +5,6 @@ * Copyright (C) 2016 Cristina-Gabriela Moraru */ #include -#include #include #include diff --git a/drivers/iio/potentiometer/mcp4018.c b/drivers/iio/potentiometer/mcp4018.c index a88bb2231850..b10b4b920dc0 100644 --- a/drivers/iio/potentiometer/mcp4018.c +++ b/drivers/iio/potentiometer/mcp4018.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #define MCP4018_WIPER_MAX 127 diff --git a/drivers/iio/potentiometer/mcp41010.c b/drivers/iio/potentiometer/mcp41010.c index f35fc4a6c55b..ed0764231224 100644 --- a/drivers/iio/potentiometer/mcp41010.c +++ b/drivers/iio/potentiometer/mcp41010.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/potentiometer/mcp4131.c b/drivers/iio/potentiometer/mcp4131.c index 56c9111ef5e8..dad09ce6a75d 100644 --- a/drivers/iio/potentiometer/mcp4131.c +++ b/drivers/iio/potentiometer/mcp4131.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/potentiometer/mcp4531.c b/drivers/iio/potentiometer/mcp4531.c index 9912e91ff7b4..7fb1fb5ab8a5 100644 --- a/drivers/iio/potentiometer/mcp4531.c +++ b/drivers/iio/potentiometer/mcp4531.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/potentiostat/lmp91000.c b/drivers/iio/potentiostat/lmp91000.c index 359dffa47091..1984d990438c 100644 --- a/drivers/iio/potentiostat/lmp91000.c +++ b/drivers/iio/potentiostat/lmp91000.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/abp2030pa_i2c.c b/drivers/iio/pressure/abp2030pa_i2c.c index e71dc8e8e957..fa4d290cfd3e 100644 --- a/drivers/iio/pressure/abp2030pa_i2c.c +++ b/drivers/iio/pressure/abp2030pa_i2c.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/pressure/abp2030pa_spi.c b/drivers/iio/pressure/abp2030pa_spi.c index eaea9a3ebf11..8bc59eb499aa 100644 --- a/drivers/iio/pressure/abp2030pa_spi.c +++ b/drivers/iio/pressure/abp2030pa_spi.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/pressure/adp810.c b/drivers/iio/pressure/adp810.c index 47c5ad564c7f..82aa433548d2 100644 --- a/drivers/iio/pressure/adp810.c +++ b/drivers/iio/pressure/adp810.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index 6cbde48d5be3..6a567b6075d9 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index a039b99d9851..ae499d197555 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index be14202855cf..ee34c8908b74 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/pressure/hsc030pa.c b/drivers/iio/pressure/hsc030pa.c index d6b18a84f0ab..0374d406b401 100644 --- a/drivers/iio/pressure/hsc030pa.c +++ b/drivers/iio/pressure/hsc030pa.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/hsc030pa_i2c.c b/drivers/iio/pressure/hsc030pa_i2c.c index f4ea30b2980d..050cacd9ea6a 100644 --- a/drivers/iio/pressure/hsc030pa_i2c.c +++ b/drivers/iio/pressure/hsc030pa_i2c.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/pressure/hsc030pa_spi.c b/drivers/iio/pressure/hsc030pa_spi.c index 5d331b3b6da8..be58e550cc12 100644 --- a/drivers/iio/pressure/hsc030pa_spi.c +++ b/drivers/iio/pressure/hsc030pa_spi.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index 02b363c5c45b..82824e3e8db9 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/mprls0025pa.c b/drivers/iio/pressure/mprls0025pa.c index e8c495f336ff..c21f0a050660 100644 --- a/drivers/iio/pressure/mprls0025pa.c +++ b/drivers/iio/pressure/mprls0025pa.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/mprls0025pa_i2c.c b/drivers/iio/pressure/mprls0025pa_i2c.c index 92edaf3005eb..06907b64a596 100644 --- a/drivers/iio/pressure/mprls0025pa_i2c.c +++ b/drivers/iio/pressure/mprls0025pa_i2c.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/pressure/mprls0025pa_spi.c b/drivers/iio/pressure/mprls0025pa_spi.c index 8c8c726f703f..23f47c04ed45 100644 --- a/drivers/iio/pressure/mprls0025pa_spi.c +++ b/drivers/iio/pressure/mprls0025pa_spi.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index b5be6a6daf02..c57ad473b21f 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -14,7 +14,6 @@ #include #include #include -#include #include diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index 25c7bd2d8fdf..c41aaa6244cd 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -9,7 +9,6 @@ #include #include #include -#include #include diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index 03945a4fc718..be8921644558 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/pressure/sdp500.c b/drivers/iio/pressure/sdp500.c index ba80dc21faad..153f335ebf1e 100644 --- a/drivers/iio/pressure/sdp500.c +++ b/drivers/iio/pressure/sdp500.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 816bfcfd62ae..2b7c84b7e6b4 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index 39827e6841ca..d843186b44af 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index 2d8af33f6a29..e04a61c2388b 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "zpa2326.h" /* diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index af756e2b0f31..73e37a77c933 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "zpa2326.h" /* diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index f1018b14aecf..3406232822cb 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/proximity/cros_ec_mkbp_proximity.c b/drivers/iio/proximity/cros_ec_mkbp_proximity.c index 1f9de7066ebf..63f9b45bef7b 100644 --- a/drivers/iio/proximity/cros_ec_mkbp_proximity.c +++ b/drivers/iio/proximity/cros_ec_mkbp_proximity.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/proximity/d3323aa.c b/drivers/iio/proximity/d3323aa.c index 30821f583454..d40e3dff9eb1 100644 --- a/drivers/iio/proximity/d3323aa.c +++ b/drivers/iio/proximity/d3323aa.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/hx9023s.c b/drivers/iio/proximity/hx9023s.c index c3a93c0e2b64..a6ff7cbe9e65 100644 --- a/drivers/iio/proximity/hx9023s.c +++ b/drivers/iio/proximity/hx9023s.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/isl29501.c b/drivers/iio/proximity/isl29501.c index 016626f21218..95fb7238f678 100644 --- a/drivers/iio/proximity/isl29501.c +++ b/drivers/iio/proximity/isl29501.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/proximity/mb1232.c b/drivers/iio/proximity/mb1232.c index 1e8ecb9e9c56..eab881b0cdc7 100644 --- a/drivers/iio/proximity/mb1232.c +++ b/drivers/iio/proximity/mb1232.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c index e3487094d7be..1e646b858468 100644 --- a/drivers/iio/proximity/ping.c +++ b/drivers/iio/proximity/ping.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 5e9e04540393..400477b4c740 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/srf04.c b/drivers/iio/proximity/srf04.c index e97f9a20ac7a..7be50bdebfcb 100644 --- a/drivers/iio/proximity/srf04.c +++ b/drivers/iio/proximity/srf04.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 602f7b95c83e..79ba46d8a0aa 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/sx9324.c b/drivers/iio/proximity/sx9324.c index 36c45d101336..13b4ef2896e3 100644 --- a/drivers/iio/proximity/sx9324.c +++ b/drivers/iio/proximity/sx9324.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/sx9360.c b/drivers/iio/proximity/sx9360.c index 4b9498022b22..ed83d809ecf5 100644 --- a/drivers/iio/proximity/sx9360.c +++ b/drivers/iio/proximity/sx9360.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/proximity/vl53l1x-i2c.c b/drivers/iio/proximity/vl53l1x-i2c.c index ff56bfcf8bd2..dc4ffbc95d1f 100644 --- a/drivers/iio/proximity/vl53l1x-i2c.c +++ b/drivers/iio/proximity/vl53l1x-i2c.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/resolver/ad2s1200.c b/drivers/iio/resolver/ad2s1200.c index c00a60cb31a5..55bcbbd4021a 100644 --- a/drivers/iio/resolver/ad2s1200.c +++ b/drivers/iio/resolver/ad2s1200.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/temperature/hid-sensor-temperature.c b/drivers/iio/temperature/hid-sensor-temperature.c index 9f628a8e5cfb..54a00253de11 100644 --- a/drivers/iio/temperature/hid-sensor-temperature.c +++ b/drivers/iio/temperature/hid-sensor-temperature.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "../common/hid-sensors/hid-sensor-trigger.h" diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index fc65d8352d12..f8c4917bb118 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c index 7ddec5cbe558..13405f3ba829 100644 --- a/drivers/iio/temperature/max31856.c +++ b/drivers/iio/temperature/max31856.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/temperature/max31865.c b/drivers/iio/temperature/max31865.c index 5a6fbe3c80e5..82cf06c4d272 100644 --- a/drivers/iio/temperature/max31865.c +++ b/drivers/iio/temperature/max31865.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index e898f56d1196..015afeab1914 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/iio/temperature/mcp9600.c b/drivers/iio/temperature/mcp9600.c index 5c1c959277b8..b0ff0c7b4891 100644 --- a/drivers/iio/temperature/mcp9600.c +++ b/drivers/iio/temperature/mcp9600.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index 342f2e4f80d1..27d6ab5f5d7a 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/temperature/mlx90632.c b/drivers/iio/temperature/mlx90632.c index 3ab7687c4146..2fde48f337e2 100644 --- a/drivers/iio/temperature/mlx90632.c +++ b/drivers/iio/temperature/mlx90632.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/temperature/mlx90635.c b/drivers/iio/temperature/mlx90635.c index 8c8bdab106dd..0f31879a4f64 100644 --- a/drivers/iio/temperature/mlx90635.c +++ b/drivers/iio/temperature/mlx90635.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/temperature/tmp006.c b/drivers/iio/temperature/tmp006.c index 43400666fce2..d9f6449ec0d8 100644 --- a/drivers/iio/temperature/tmp006.c +++ b/drivers/iio/temperature/tmp006.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c index d9eea06ff540..2f6ff87d2a37 100644 --- a/drivers/iio/temperature/tmp007.c +++ b/drivers/iio/temperature/tmp007.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/drivers/iio/temperature/tsys01.c b/drivers/iio/temperature/tsys01.c index 31ba2c941486..28b3ce022ce7 100644 --- a/drivers/iio/temperature/tsys01.c +++ b/drivers/iio/temperature/tsys01.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/trigger/stm32-lptimer-trigger.c b/drivers/iio/trigger/stm32-lptimer-trigger.c index c7bab18221c7..828890fe353c 100644 --- a/drivers/iio/trigger/stm32-lptimer-trigger.c +++ b/drivers/iio/trigger/stm32-lptimer-trigger.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c index 3b9a3a6cbb25..4f6ff1e72f2e 100644 --- a/drivers/iio/trigger/stm32-timer-trigger.c +++ b/drivers/iio/trigger/stm32-timer-trigger.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/keyboard/adp5585-keys.c b/drivers/input/keyboard/adp5585-keys.c index 4208229e1356..017c95029180 100644 --- a/drivers/input/keyboard/adp5585-keys.c +++ b/drivers/input/keyboard/adp5585-keys.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 8d14d0f69d4e..40371f5bd9ba 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/keyboard/charlieplex_keypad.c b/drivers/input/keyboard/charlieplex_keypad.c index 6dbb5c183f02..d222b622c820 100644 --- a/drivers/input/keyboard/charlieplex_keypad.c +++ b/drivers/input/keyboard/charlieplex_keypad.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c index 4c1a3e611edd..ddabd789861b 100644 --- a/drivers/input/keyboard/clps711x-keypad.c +++ b/drivers/input/keyboard/clps711x-keypad.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c index 817c23438f6e..9ea926a4c95b 100644 --- a/drivers/input/keyboard/ep93xx_keypad.c +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff --git a/drivers/input/keyboard/max7360-keypad.c b/drivers/input/keyboard/max7360-keypad.c index 503be952b0a6..1e5251f87f6f 100644 --- a/drivers/input/keyboard/max7360-keypad.c +++ b/drivers/input/keyboard/max7360-keypad.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/keyboard/pinephone-keyboard.c b/drivers/input/keyboard/pinephone-keyboard.c index 147b1f288a33..86f21045c69b 100644 --- a/drivers/input/keyboard/pinephone-keyboard.c +++ b/drivers/input/keyboard/pinephone-keyboard.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/ariel-pwrbutton.c b/drivers/input/misc/ariel-pwrbutton.c index cdc80715b5fd..f0e06ee604d6 100644 --- a/drivers/input/misc/ariel-pwrbutton.c +++ b/drivers/input/misc/ariel-pwrbutton.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index c338765e0ecd..830714241788 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c index f0759dd39b35..0e4a49845afa 100644 --- a/drivers/input/misc/gpio_decoder.c +++ b/drivers/input/misc/gpio_decoder.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c index 1851848e2cd3..7a576f65bfca 100644 --- a/drivers/input/misc/iqs269a.c +++ b/drivers/input/misc/iqs269a.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c index 7fba4a8edceb..bc50dfba9e6c 100644 --- a/drivers/input/misc/iqs626a.c +++ b/drivers/input/misc/iqs626a.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index ff23219a582a..ace489482734 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index a2888d1ff58f..403659a08c61 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -11,7 +11,6 @@ #include #include #include -#include #define MMA8450_DRV_NAME "mma8450" diff --git a/drivers/input/misc/rt5120-pwrkey.c b/drivers/input/misc/rt5120-pwrkey.c index 8a8c1aeeed05..2262f5057d9f 100644 --- a/drivers/input/misc/rt5120-pwrkey.c +++ b/drivers/input/misc/rt5120-pwrkey.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/input/misc/sc27xx-vibra.c b/drivers/input/misc/sc27xx-vibra.c index 1478017f0968..7590f3a91db8 100644 --- a/drivers/input/misc/sc27xx-vibra.c +++ b/drivers/input/misc/sc27xx-vibra.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index b0feef19515d..3e94a5995766 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c index a9812789771c..6a9adcca41e4 100644 --- a/drivers/input/serio/sun4i-ps2.c +++ b/drivers/input/serio/sun4i-ps2.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #define DRIVER_NAME "sun4i-ps2" diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 73c397e44da4..9266c07314be 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/himax_hx852x.c b/drivers/input/touchscreen/himax_hx852x.c index 83c60e137a55..1c488a63e53b 100644 --- a/drivers/input/touchscreen/himax_hx852x.c +++ b/drivers/input/touchscreen/himax_hx852x.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/hynitron_cstxxx.c b/drivers/input/touchscreen/hynitron_cstxxx.c index 1d8ca90dcda6..f6139b1a8681 100644 --- a/drivers/input/touchscreen/hynitron_cstxxx.c +++ b/drivers/input/touchscreen/hynitron_cstxxx.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 66ada7ffbc80..3479698f55e3 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index b9bbe8b3eab8..c3cc37274335 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/msg2638.c b/drivers/input/touchscreen/msg2638.c index 240d2eebf1c9..cd40c284d6f4 100644 --- a/drivers/input/touchscreen/msg2638.c +++ b/drivers/input/touchscreen/msg2638.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index 7e761ec73273..68f7e2e28f37 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 4a775c5df0ea..e4d7da0f4434 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include "tsc2007.h" diff --git a/drivers/interconnect/mediatek/mt8183.c b/drivers/interconnect/mediatek/mt8183.c index c212e79334cf..ed607a8b86cf 100644 --- a/drivers/interconnect/mediatek/mt8183.c +++ b/drivers/interconnect/mediatek/mt8183.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/mediatek/mt8195.c b/drivers/interconnect/mediatek/mt8195.c index 3ca23469ab18..0f0767639f19 100644 --- a/drivers/interconnect/mediatek/mt8195.c +++ b/drivers/interconnect/mediatek/mt8195.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/mediatek/mt8196.c b/drivers/interconnect/mediatek/mt8196.c index e9af32065be1..df5a975f0ad6 100644 --- a/drivers/interconnect/mediatek/mt8196.c +++ b/drivers/interconnect/mediatek/mt8196.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/msm8909.c b/drivers/interconnect/qcom/msm8909.c index dd656ce7b64d..e222cba14b8e 100644 --- a/drivers/interconnect/qcom/msm8909.c +++ b/drivers/interconnect/qcom/msm8909.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/msm8937.c b/drivers/interconnect/qcom/msm8937.c index 58533d00266b..a9a84f276e1b 100644 --- a/drivers/interconnect/qcom/msm8937.c +++ b/drivers/interconnect/qcom/msm8937.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/msm8939.c b/drivers/interconnect/qcom/msm8939.c index b52c5ac1175c..fe249e906259 100644 --- a/drivers/interconnect/qcom/msm8939.c +++ b/drivers/interconnect/qcom/msm8939.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/interconnect/qcom/msm8953.c b/drivers/interconnect/qcom/msm8953.c index 94a9773d2970..3ae376b63739 100644 --- a/drivers/interconnect/qcom/msm8953.c +++ b/drivers/interconnect/qcom/msm8953.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/msm8976.c b/drivers/interconnect/qcom/msm8976.c index 4e2ac7ebe742..c219dcfd43b6 100644 --- a/drivers/interconnect/qcom/msm8976.c +++ b/drivers/interconnect/qcom/msm8976.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/msm8996.c b/drivers/interconnect/qcom/msm8996.c index 84cfafb22aa1..882f9d2b6d4e 100644 --- a/drivers/interconnect/qcom/msm8996.c +++ b/drivers/interconnect/qcom/msm8996.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/qcm2290.c b/drivers/interconnect/qcom/qcm2290.c index e120bc1395f3..d4a8142c6ac4 100644 --- a/drivers/interconnect/qcom/qcm2290.c +++ b/drivers/interconnect/qcom/qcm2290.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/qcs404.c b/drivers/interconnect/qcom/qcs404.c index ceac7a698769..fdd9f908a48b 100644 --- a/drivers/interconnect/qcom/qcs404.c +++ b/drivers/interconnect/qcom/qcs404.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/interconnect/qcom/qdu1000.c b/drivers/interconnect/qcom/qdu1000.c index 0006413241dc..5fd6eee0568f 100644 --- a/drivers/interconnect/qcom/qdu1000.c +++ b/drivers/interconnect/qcom/qdu1000.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sa8775p.c b/drivers/interconnect/qcom/sa8775p.c index 6a49abc96efe..998a22d9d46d 100644 --- a/drivers/interconnect/qcom/sa8775p.c +++ b/drivers/interconnect/qcom/sa8775p.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sc7180.c b/drivers/interconnect/qcom/sc7180.c index 0ea06facf81e..a2f5445c1954 100644 --- a/drivers/interconnect/qcom/sc7180.c +++ b/drivers/interconnect/qcom/sc7180.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c index c4cb6443f2d4..da21db2bdb7f 100644 --- a/drivers/interconnect/qcom/sc7280.c +++ b/drivers/interconnect/qcom/sc7280.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c index c9bf1af54e37..fef77cd2bf69 100644 --- a/drivers/interconnect/qcom/sc8180x.c +++ b/drivers/interconnect/qcom/sc8180x.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/interconnect/qcom/sc8280xp.c b/drivers/interconnect/qcom/sc8280xp.c index ed2161da37bf..4110536664d0 100644 --- a/drivers/interconnect/qcom/sc8280xp.c +++ b/drivers/interconnect/qcom/sc8280xp.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sdm660.c b/drivers/interconnect/qcom/sdm660.c index 7392bebba334..d8c979a12235 100644 --- a/drivers/interconnect/qcom/sdm660.c +++ b/drivers/interconnect/qcom/sdm660.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sdm670.c b/drivers/interconnect/qcom/sdm670.c index 88f4768b765c..9280921d44d2 100644 --- a/drivers/interconnect/qcom/sdm670.c +++ b/drivers/interconnect/qcom/sdm670.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c index 6d5bbeda0689..1c434fd12ead 100644 --- a/drivers/interconnect/qcom/sdm845.c +++ b/drivers/interconnect/qcom/sdm845.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/interconnect/qcom/sdx55.c b/drivers/interconnect/qcom/sdx55.c index 75ced1286919..876788a14e6e 100644 --- a/drivers/interconnect/qcom/sdx55.c +++ b/drivers/interconnect/qcom/sdx55.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sdx65.c b/drivers/interconnect/qcom/sdx65.c index 6c5b4e1ec82f..92003df39ea4 100644 --- a/drivers/interconnect/qcom/sdx65.c +++ b/drivers/interconnect/qcom/sdx65.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/shikra.c b/drivers/interconnect/qcom/shikra.c index bc40d1592fb3..c5593a08c01a 100644 --- a/drivers/interconnect/qcom/shikra.c +++ b/drivers/interconnect/qcom/shikra.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sm6115.c b/drivers/interconnect/qcom/sm6115.c index 3ee12c8a4d56..e1cd898bc943 100644 --- a/drivers/interconnect/qcom/sm6115.c +++ b/drivers/interconnect/qcom/sm6115.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sm6350.c b/drivers/interconnect/qcom/sm6350.c index d96bec1cbb26..c098c608b836 100644 --- a/drivers/interconnect/qcom/sm6350.c +++ b/drivers/interconnect/qcom/sm6350.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sm7150.c b/drivers/interconnect/qcom/sm7150.c index 0390d0468b48..d212a50e3cbb 100644 --- a/drivers/interconnect/qcom/sm7150.c +++ b/drivers/interconnect/qcom/sm7150.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sm8150.c b/drivers/interconnect/qcom/sm8150.c index ae732afbd155..eb1e61599e3a 100644 --- a/drivers/interconnect/qcom/sm8150.c +++ b/drivers/interconnect/qcom/sm8150.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c index 2ed112eab155..2b811b5cd216 100644 --- a/drivers/interconnect/qcom/sm8250.c +++ b/drivers/interconnect/qcom/sm8250.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c index bb793d724893..d92c26bee595 100644 --- a/drivers/interconnect/qcom/sm8350.c +++ b/drivers/interconnect/qcom/sm8350.c @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c index c88327d200ac..54c860b16eb0 100644 --- a/drivers/interconnect/qcom/sm8450.c +++ b/drivers/interconnect/qcom/sm8450.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/interconnect/qcom/sm8550.c b/drivers/interconnect/qcom/sm8550.c index d01762e13272..535097eab537 100644 --- a/drivers/interconnect/qcom/sm8550.c +++ b/drivers/interconnect/qcom/sm8550.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c index 65e0ef6539fe..531b29fbf492 100644 --- a/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c +++ b/drivers/iommu/arm/arm-smmu/arm-smmu-qcom-debug.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index b57d81ad33a0..6f5811aae59c 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -3290,11 +3290,9 @@ static void its_cpu_init_collection(struct its_node *its) /* avoid cross node collections and its mapping */ if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) { - struct device_node *cpu_node; + struct device_node *cpu_node __free(device_node) = of_get_cpu_node(cpu, NULL); - cpu_node = of_get_cpu_node(cpu, NULL); - if (its->numa_node != NUMA_NO_NODE && - its->numa_node != of_node_to_nid(cpu_node)) + if (its->numa_node != NUMA_NO_NODE && its->numa_node != of_node_to_nid(cpu_node)) return; } diff --git a/drivers/irqchip/irq-imx-intmux.c b/drivers/irqchip/irq-imx-intmux.c index 5f9b204d350b..47c2681d138a 100644 --- a/drivers/irqchip/irq-imx-intmux.c +++ b/drivers/irqchip/irq-imx-intmux.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/irqchip/irq-lan966x-oic.c b/drivers/irqchip/irq-lan966x-oic.c index 11d3a0ffa261..8af08d0e4182 100644 --- a/drivers/irqchip/irq-lan966x-oic.c +++ b/drivers/irqchip/irq-lan966x-oic.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/irqchip/irq-riscv-imsic-early.c b/drivers/irqchip/irq-riscv-imsic-early.c index a7a1852b548c..12efd241ce88 100644 --- a/drivers/irqchip/irq-riscv-imsic-early.c +++ b/drivers/irqchip/irq-riscv-imsic-early.c @@ -272,16 +272,13 @@ static int __init imsic_early_acpi_init(union acpi_subtable_headers *header, rc = imsic_setup_state(imsic_acpi_fwnode, imsic); if (rc) { pr_err("%pfwP: failed to setup state (error %d)\n", imsic_acpi_fwnode, rc); - return rc; + goto cleanup; } /* Do early setup of IMSIC state and IPIs */ rc = imsic_early_probe(imsic_acpi_fwnode); - if (rc) { - irq_domain_free_fwnode(imsic_acpi_fwnode); - imsic_acpi_fwnode = NULL; - return rc; - } + if (rc) + goto cleanup; rc = imsic_platform_acpi_probe(imsic_acpi_fwnode); @@ -300,8 +297,12 @@ static int __init imsic_early_acpi_init(union acpi_subtable_headers *header, * DT where IPI works but MSI probe fails for some reason. */ return 0; -} +cleanup: + irq_domain_free_fwnode(imsic_acpi_fwnode); + imsic_acpi_fwnode = NULL; + return rc; +} IRQCHIP_ACPI_DECLARE(riscv_imsic, ACPI_MADT_TYPE_IMSIC, NULL, 1, imsic_early_acpi_init); #endif diff --git a/drivers/irqchip/irq-sl28cpld.c b/drivers/irqchip/irq-sl28cpld.c index e50f9eaba4cd..9892c020e0be 100644 --- a/drivers/irqchip/irq-sl28cpld.c +++ b/drivers/irqchip/irq-sl28cpld.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/irqchip/irq-stm32mp-exti.c b/drivers/irqchip/irq-stm32mp-exti.c index a24f4f1a4f8f..bf3a2def69ca 100644 --- a/drivers/irqchip/irq-stm32mp-exti.c +++ b/drivers/irqchip/irq-stm32mp-exti.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c index 2e4013c6834d..c7c0b155e353 100644 --- a/drivers/irqchip/irq-ts4800.c +++ b/drivers/irqchip/irq-ts4800.c @@ -28,6 +28,7 @@ struct ts4800_irq_data { void __iomem *base; struct platform_device *pdev; struct irq_domain *domain; + unsigned int parent_irq; }; static void ts4800_irq_mask(struct irq_data *d) @@ -134,6 +135,7 @@ static int ts4800_ic_probe(struct platform_device *pdev) irq_set_chained_handler_and_data(parent_irq, ts4800_ic_chained_handle_irq, data); + data->parent_irq = parent_irq; platform_set_drvdata(pdev, data); return 0; @@ -142,6 +144,14 @@ static int ts4800_ic_probe(struct platform_device *pdev) static void ts4800_ic_remove(struct platform_device *pdev) { struct ts4800_irq_data *data = platform_get_drvdata(pdev); + unsigned int hwirq; + + irq_set_chained_handler_and_data(data->parent_irq, NULL, NULL); + + for (hwirq = 0; hwirq < 8; hwirq++) + irq_dispose_mapping(irq_find_mapping(data->domain, hwirq)); + + irq_dispose_mapping(data->parent_irq); irq_domain_remove(data->domain); } diff --git a/drivers/leds/flash/leds-rt8515.c b/drivers/leds/flash/leds-rt8515.c index f6b439674c03..00904cc90ed6 100644 --- a/drivers/leds/flash/leds-rt8515.c +++ b/drivers/leds/flash/leds-rt8515.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-aw200xx.c b/drivers/leds/leds-aw200xx.c index 0d90eeb6448f..b92158ac9ce3 100644 --- a/drivers/leds/leds-aw200xx.c +++ b/drivers/leds/leds-aw200xx.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-bd2606mvv.c b/drivers/leds/leds-bd2606mvv.c index c1181a35d0f7..4c696abfd23d 100644 --- a/drivers/leds/leds-bd2606mvv.c +++ b/drivers/leds/leds-bd2606mvv.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-cht-wcove.c b/drivers/leds/leds-cht-wcove.c index 9a609dd5acdc..da05ff94898d 100644 --- a/drivers/leds/leds-cht-wcove.c +++ b/drivers/leds/leds-cht-wcove.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-cr0014114.c b/drivers/leds/leds-cr0014114.c index 7e51c374edd4..3f6931ae0bcc 100644 --- a/drivers/leds/leds-cr0014114.c +++ b/drivers/leds/leds-cr0014114.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include diff --git a/drivers/leds/leds-cros_ec.c b/drivers/leds/leds-cros_ec.c index 6592ceee866a..1844d0cd5f52 100644 --- a/drivers/leds/leds-cros_ec.c +++ b/drivers/leds/leds-cros_ec.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-el15203000.c b/drivers/leds/leds-el15203000.c index e26d1654bd0d..8e8ddd7c514d 100644 --- a/drivers/leds/leds-el15203000.c +++ b/drivers/leds/leds-el15203000.c @@ -4,7 +4,6 @@ #include #include -#include #include #include #include diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index a3428b22de3a..8ae71c2e91e0 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-is31fl319x.c b/drivers/leds/leds-is31fl319x.c index 80f38dba0fba..5206082b7722 100644 --- a/drivers/leds/leds-is31fl319x.c +++ b/drivers/leds/leds-is31fl319x.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-lm36274.c b/drivers/leds/leds-lm36274.c index e009b6d17915..7fd8365c2f7b 100644 --- a/drivers/leds/leds-lm36274.c +++ b/drivers/leds/leds-lm36274.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-lm3692x.c b/drivers/leds/leds-lm3692x.c index 95b850a3b31c..8d2678dc9e4f 100644 --- a/drivers/leds/leds-lm3692x.c +++ b/drivers/leds/leds-lm3692x.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-lm3697.c b/drivers/leds/leds-lm3697.c index 933191fb2be0..83dc607a6987 100644 --- a/drivers/leds/leds-lm3697.c +++ b/drivers/leds/leds-lm3697.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-lp50xx.c b/drivers/leds/leds-lp50xx.c index 259169214aaf..20bfb315bda1 100644 --- a/drivers/leds/leds-lp50xx.c +++ b/drivers/leds/leds-lp50xx.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c index d0160fde0f94..6fca14e76ca6 100644 --- a/drivers/leds/leds-lt3593.c +++ b/drivers/leds/leds-lt3593.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/leds/leds-max5970.c b/drivers/leds/leds-max5970.c index a1e91a06249c..cb4dd0a9166c 100644 --- a/drivers/leds/leds-max5970.c +++ b/drivers/leds/leds-max5970.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-mlxcpld.c b/drivers/leds/leds-mlxcpld.c index f25f68789281..1f5ab8fbdaf9 100644 --- a/drivers/leds/leds-mlxcpld.c +++ b/drivers/leds/leds-mlxcpld.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include diff --git a/drivers/leds/leds-nic78bx.c b/drivers/leds/leds-nic78bx.c index f3161266b8ad..5e3098e1e1ad 100644 --- a/drivers/leds/leds-nic78bx.c +++ b/drivers/leds/leds-nic78bx.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/leds-pca995x.c b/drivers/leds/leds-pca995x.c index 59951207fd04..fee6216cd1bd 100644 --- a/drivers/leds/leds-pca995x.c +++ b/drivers/leds/leds-pca995x.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c index ade64629431a..5ba0f36b2d81 100644 --- a/drivers/leds/leds-regulator.c +++ b/drivers/leds/leds-regulator.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/leds/leds-spi-byte.c b/drivers/leds/leds-spi-byte.c index d24d0ddf347c..0217557aad57 100644 --- a/drivers/leds/leds-spi-byte.c +++ b/drivers/leds/leds-spi-byte.c @@ -29,7 +29,6 @@ */ #include -#include #include #include #include diff --git a/drivers/leds/leds-sun50i-a100.c b/drivers/leds/leds-sun50i-a100.c index 2c9bd360ab81..7cfb4c7390bf 100644 --- a/drivers/leds/leds-sun50i-a100.c +++ b/drivers/leds/leds-sun50i-a100.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/rgb/leds-group-multicolor.c b/drivers/leds/rgb/leds-group-multicolor.c index 548c7dd63ba1..a707d51c6a4b 100644 --- a/drivers/leds/rgb/leds-group-multicolor.c +++ b/drivers/leds/rgb/leds-group-multicolor.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/leds/rgb/leds-mt6370-rgb.c b/drivers/leds/rgb/leds-mt6370-rgb.c index c5927d0eb830..2c0ccd1ba7fb 100644 --- a/drivers/leds/rgb/leds-mt6370-rgb.c +++ b/drivers/leds/rgb/leds-mt6370-rgb.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/leds/rgb/leds-pwm-multicolor.c b/drivers/leds/rgb/leds-pwm-multicolor.c index e0d7d3c9215c..d5b303aab5d6 100644 --- a/drivers/leds/rgb/leds-pwm-multicolor.c +++ b/drivers/leds/rgb/leds-pwm-multicolor.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mailbox/mailbox-mpfs.c b/drivers/mailbox/mailbox-mpfs.c index ef40fe2be30d..6c40d865b3f1 100644 --- a/drivers/mailbox/mailbox-mpfs.c +++ b/drivers/mailbox/mailbox-mpfs.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mailbox/platform_mhu.c b/drivers/mailbox/platform_mhu.c index 834aecd720ac..176ce290b8a8 100644 --- a/drivers/mailbox/platform_mhu.c +++ b/drivers/mailbox/platform_mhu.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c index ec1da9cd3674..1fe9c537671d 100644 --- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c +++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/firewire/firedtv-fw.c b/drivers/media/firewire/firedtv-fw.c index c348526a4c45..887d429668ed 100644 --- a/drivers/media/firewire/firedtv-fw.c +++ b/drivers/media/firewire/firedtv-fw.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index e5d11a6e6766..a1c7f68225b4 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -5,7 +5,6 @@ * Copyright (C) 2013 Cogent Embedded, Inc. * Copyright (C) 2013 Renesas Solutions Corp. */ -#include #include #include #include diff --git a/drivers/media/i2c/cvs/core.c b/drivers/media/i2c/cvs/core.c index 4282f33c7295..fe9e59ac311c 100644 --- a/drivers/media/i2c/cvs/core.c +++ b/drivers/media/i2c/cvs/core.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c index cbcda0e18ff1..15900d5414cf 100644 --- a/drivers/media/i2c/gc0308.c +++ b/drivers/media/i2c/gc0308.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c index 8ba17f80fffe..7cf7cde1f936 100644 --- a/drivers/media/i2c/gc05a2.c +++ b/drivers/media/i2c/gc05a2.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c index 11fd936db9c3..4144aad8f2da 100644 --- a/drivers/media/i2c/gc08a3.c +++ b/drivers/media/i2c/gc08a3.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index c3c90d830ee2..6b28a5fcd2da 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index e395e2d14e97..848ea06e70ab 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 8dc57eeba606..d21510caf45a 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index d4359d5b92bb..5113826534d7 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 78e63bd1b35b..5f1938c7a944 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 92d2d6cd4ba4..8deb5f5501fa 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 04b3183b7bcb..01fa892de079 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index 508149485248..1c31b2a57eea 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index 78b62c169b99..ed59b4818c55 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 27afc3fc0175..311c61d9e25d 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index b6d238ba0d53..4d040e9feeac 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -10,7 +10,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index a8586df14f77..8c9cd769fa01 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/t4ka3.c b/drivers/media/i2c/t4ka3.c index 746548868bb0..a5a68e3fbec2 100644 --- a/drivers/media/i2c/t4ka3.c +++ b/drivers/media/i2c/t4ka3.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 376eecb0b673..99ace2acdb35 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -18,7 +18,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 56b99eea54a1..6b50fb422a61 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/arm/mali-c55/mali-c55-core.c b/drivers/media/platform/arm/mali-c55/mali-c55-core.c index ee4a4267415e..94a389b3f833 100644 --- a/drivers/media/platform/arm/mali-c55/mali-c55-core.c +++ b/drivers/media/platform/arm/mali-c55/mali-c55-core.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/chips-media/coda/imx-vdoa.c b/drivers/media/platform/chips-media/coda/imx-vdoa.c index be874f18a365..cd085c1c73f4 100644 --- a/drivers/media/platform/chips-media/coda/imx-vdoa.c +++ b/drivers/media/platform/chips-media/coda/imx-vdoa.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c index b6f5b2249f1f..b312a15d707b 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_enc_hw.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c index 70303a0b6919..e69292f3b2a9 100644 --- a/drivers/media/platform/microchip/microchip-csi2dc.c +++ b/drivers/media/platform/microchip/microchip-csi2dc.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index daa8f56610c7..6a43ea191da1 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index bf53267cb68d..79acf7c1ec9a 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -5,7 +5,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/media/platform/renesas/rcar-fcp.c b/drivers/media/platform/renesas/rcar-fcp.c index f90c86bbce6e..dfb0ca93e854 100644 --- a/drivers/media/platform/renesas/rcar-fcp.c +++ b/drivers/media/platform/renesas/rcar-fcp.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c index 3c5fbd857371..798ef2916262 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c index 645e4f155dd0..33b768774e20 100644 --- a/drivers/media/platform/st/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index f4075576ef1d..65bc426e5aac 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c index 12e438c678f9..7bff23d1ea98 100644 --- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c +++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/ti/vpe/vip.c b/drivers/media/platform/ti/vpe/vip.c index cb0a5a07a3d4..e56a95f53ea9 100644 --- a/drivers/media/platform/ti/vpe/vip.c +++ b/drivers/media/platform/ti/vpe/vip.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index 392441e0c116..31eb58b06c70 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 21c912403efc..711f281613f5 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/drivers/memory/stm32_omm.c b/drivers/memory/stm32_omm.c index 5d06623f3f68..0e891396bdb6 100644 --- a/drivers/memory/stm32_omm.c +++ b/drivers/memory/stm32_omm.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index f71265b303b9..2a4cb64c4c4c 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/memory/tegra/tegra186.c b/drivers/memory/tegra/tegra186.c index 579d058da220..442edb2b033e 100644 --- a/drivers/memory/tegra/tegra186.c +++ b/drivers/memory/tegra/tegra186.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/memory/tegra/tegra210-emc-core.c b/drivers/memory/tegra/tegra210-emc-core.c index 065ae8bc2830..e8d4cd8fdec2 100644 --- a/drivers/memory/tegra/tegra210-emc-core.c +++ b/drivers/memory/tegra/tegra210-emc-core.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/adp5585.c b/drivers/mfd/adp5585.c index 46b3ce3d7bae..aad1d734baeb 100644 --- a/drivers/mfd/adp5585.c +++ b/drivers/mfd/adp5585.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c index 0b541c0d3b1b..2a3a05122176 100644 --- a/drivers/mfd/atmel-hlcdc.c +++ b/drivers/mfd/atmel-hlcdc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mfd/atmel-smc.c b/drivers/mfd/atmel-smc.c index 0a5b42c83f17..e69be61511a4 100644 --- a/drivers/mfd/atmel-smc.c +++ b/drivers/mfd/atmel-smc.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/cros_ec_dev.c b/drivers/mfd/cros_ec_dev.c index 11ee1146cf71..e253c753beb6 100644 --- a/drivers/mfd/cros_ec_dev.c +++ b/drivers/mfd/cros_ec_dev.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/cs42l43-i2c.c b/drivers/mfd/cs42l43-i2c.c index 0a0ab5e549a5..44ad63129b3f 100644 --- a/drivers/mfd/cs42l43-i2c.c +++ b/drivers/mfd/cs42l43-i2c.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/cs42l43-sdw.c b/drivers/mfd/cs42l43-sdw.c index 794c98378175..1804b942bdb5 100644 --- a/drivers/mfd/cs42l43-sdw.c +++ b/drivers/mfd/cs42l43-sdw.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index 3b4ffcbbee20..5cb392892c19 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c index 63406026d809..d4b24a717848 100644 --- a/drivers/mfd/intel-lpss-acpi.c +++ b/drivers/mfd/intel-lpss-acpi.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index f7c592dd7e87..63a3fb58566e 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 9d89171d83f9..117517c171b5 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 41429f9bcb69..627a89334908 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index c2008d2dc95a..b64729918dfd 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/lochnagar-i2c.c b/drivers/mfd/lochnagar-i2c.c index 6c930c57f2e2..9d60a42745fc 100644 --- a/drivers/mfd/lochnagar-i2c.c +++ b/drivers/mfd/lochnagar-i2c.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/lp873x.c b/drivers/mfd/lp873x.c index e8c5c89c2a76..d2c90302bf59 100644 --- a/drivers/mfd/lp873x.c +++ b/drivers/mfd/lp873x.c @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/drivers/mfd/lp87565.c b/drivers/mfd/lp87565.c index 9488d3793c10..b78ae79df5fa 100644 --- a/drivers/mfd/lp87565.c +++ b/drivers/mfd/lp87565.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 7e7e8af9af22..da275a04a1ef 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mfd/max7360.c b/drivers/mfd/max7360.c index 5ee459c490ec..52fffed0c0dd 100644 --- a/drivers/mfd/max7360.c +++ b/drivers/mfd/max7360.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/max77759.c b/drivers/mfd/max77759.c index b50433e7b3d3..72b608a1ab3f 100644 --- a/drivers/mfd/max77759.c +++ b/drivers/mfd/max77759.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/max77843.c b/drivers/mfd/max77843.c index fcff0c498c0f..2a48577b1a79 100644 --- a/drivers/mfd/max77843.c +++ b/drivers/mfd/max77843.c @@ -13,7 +13,6 @@ #include #include #include -#include #include static const struct mfd_cell max77843_devs[] = { diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c index 9f438d5d4326..56d2e57b7d73 100644 --- a/drivers/mfd/mc13xxx-spi.c +++ b/drivers/mfd/mc13xxx-spi.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mfd/motorola-cpcap.c b/drivers/mfd/motorola-cpcap.c index d8243b956f87..feeccb2c6655 100644 --- a/drivers/mfd/motorola-cpcap.c +++ b/drivers/mfd/motorola-cpcap.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mfd/ocelot-spi.c b/drivers/mfd/ocelot-spi.c index 1fed9878c323..fc30663824bb 100644 --- a/drivers/mfd/ocelot-spi.c +++ b/drivers/mfd/ocelot-spi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c index 2204bf1c5a51..072fd4447245 100644 --- a/drivers/mfd/rt5033.c +++ b/drivers/mfd/rt5033.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mfd/rt5120.c b/drivers/mfd/rt5120.c index 58d9a124d795..a229eb292484 100644 --- a/drivers/mfd/rt5120.c +++ b/drivers/mfd/rt5120.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #define RT5120_REG_INTENABLE 0x1D diff --git a/drivers/mfd/rz-mtu3.c b/drivers/mfd/rz-mtu3.c index 3fa7dfe71386..0a254e61ec0a 100644 --- a/drivers/mfd/rz-mtu3.c +++ b/drivers/mfd/rz-mtu3.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/sec-acpm.c b/drivers/mfd/sec-acpm.c index 3397d13d3b7f..d11fbf5b94b7 100644 --- a/drivers/mfd/sec-acpm.c +++ b/drivers/mfd/sec-acpm.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/sec-i2c.c b/drivers/mfd/sec-i2c.c index d8609886fcc8..4eec8f7ceee3 100644 --- a/drivers/mfd/sec-i2c.c +++ b/drivers/mfd/sec-i2c.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/simple-mfd-i2c.c b/drivers/mfd/simple-mfd-i2c.c index 52c81b18750e..ef3ce4bdf98b 100644 --- a/drivers/mfd/simple-mfd-i2c.c +++ b/drivers/mfd/simple-mfd-i2c.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/tps6594-i2c.c b/drivers/mfd/tps6594-i2c.c index 7ff7516286fd..d2269f14f068 100644 --- a/drivers/mfd/tps6594-i2c.c +++ b/drivers/mfd/tps6594-i2c.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mfd/tps6594-spi.c b/drivers/mfd/tps6594-spi.c index 944b7313a1d9..bb95d6b64cb4 100644 --- a/drivers/mfd/tps6594-spi.c +++ b/drivers/mfd/tps6594-spi.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/mfd/upboard-fpga.c b/drivers/mfd/upboard-fpga.c index afce623bbba5..9a9599dcb0a1 100644 --- a/drivers/mfd/upboard-fpga.c +++ b/drivers/mfd/upboard-fpga.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index e7e68929275e..df8e76e000cc 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 5d5f357a1996..772c4d9fa651 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/misc/eeprom/ee1004.c b/drivers/misc/eeprom/ee1004.c index e13f9fdd9d7b..923f404a44c0 100644 --- a/drivers/misc/eeprom/ee1004.c +++ b/drivers/misc/eeprom/ee1004.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 5230e910a1d1..f9c3ab52c2f9 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c index 60c42170d147..e056d2dea8c3 100644 --- a/drivers/misc/eeprom/idt_89hpesx.c +++ b/drivers/misc/eeprom/idt_89hpesx.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c index 2c6e448a47f1..79f06001259b 100644 --- a/drivers/misc/hisi_hikey_usb.c +++ b/drivers/misc/hisi_hikey_usb.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/misc/pvpanic/pvpanic-mmio.c b/drivers/misc/pvpanic/pvpanic-mmio.c index f3f2113a54a7..bedcda9b6ac5 100644 --- a/drivers/misc/pvpanic/pvpanic-mmio.c +++ b/drivers/misc/pvpanic/pvpanic-mmio.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index 17c0eb549463..b57d773f6876 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/misc/smpro-errmon.c b/drivers/misc/smpro-errmon.c index c12035a46585..56952fd96cb8 100644 --- a/drivers/misc/smpro-errmon.c +++ b/drivers/misc/smpro-errmon.c @@ -6,7 +6,6 @@ * */ -#include #include #include #include diff --git a/drivers/misc/smpro-misc.c b/drivers/misc/smpro-misc.c index 6c427141e51b..2ca5e3bcc215 100644 --- a/drivers/misc/smpro-misc.c +++ b/drivers/misc/smpro-misc.c @@ -4,7 +4,6 @@ * * Copyright (c) 2022, Ampere Computing LLC */ -#include #include #include #include diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c index 3655542ca998..06a6f24702e0 100644 --- a/drivers/mmc/host/litex_mmc.c +++ b/drivers/mmc/host/litex_mmc.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c index dc585726b66e..349082d76a99 100644 --- a/drivers/mmc/host/owl-mmc.c +++ b/drivers/mmc/host/owl-mmc.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 024edc4e5fe6..0c3967f758c2 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 9215600f03a2..426308b73b49 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/sdhci-npcm.c b/drivers/mmc/host/sdhci-npcm.c index 71b635dfdf1d..72976cd9b121 100644 --- a/drivers/mmc/host/sdhci-npcm.c +++ b/drivers/mmc/host/sdhci-npcm.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mmc/host/sdhci-of-ma35d1.c b/drivers/mmc/host/sdhci-of-ma35d1.c index 287026422616..a3b676894838 100644 --- a/drivers/mmc/host/sdhci-of-ma35d1.c +++ b/drivers/mmc/host/sdhci-of-ma35d1.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index bf899c8e38f5..9831956de1c8 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 8dbcff53a631..fe4c0f6d73f3 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c index 950923d977b7..8ed64613fda5 100644 --- a/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c +++ b/drivers/mtd/nand/raw/brcmnand/brcmstb_nand.c @@ -5,7 +5,6 @@ #include #include -#include #include #include "brcmnand.h" diff --git a/drivers/mux/adgs1408.c b/drivers/mux/adgs1408.c index 5eaf07d09ac9..af63862996d0 100644 --- a/drivers/mux/adgs1408.c +++ b/drivers/mux/adgs1408.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 4cc3202c58f3..f9c7863e51b8 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/can/spi/hi311x.c b/drivers/net/can/spi/hi311x.c index 91b1fa970f8f..ae90e6716de5 100644 --- a/drivers/net/can/spi/hi311x.c +++ b/drivers/net/can/spi/hi311x.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c index 92a86083c896..f441f2265299 100644 --- a/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c +++ b/drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/dsa/microchip/ksz8863_smi.c b/drivers/net/dsa/microchip/ksz8863_smi.c index ba08d2cf8e99..2ed122c17e32 100644 --- a/drivers/net/dsa/microchip/ksz8863_smi.c +++ b/drivers/net/dsa/microchip/ksz8863_smi.c @@ -5,7 +5,6 @@ * Copyright (C) 2019 Pengutronix, Michael Grzeschik */ -#include #include #include "ksz8.h" diff --git a/drivers/net/dsa/mt7530-mmio.c b/drivers/net/dsa/mt7530-mmio.c index 1dc8b93fb51a..119fdd863d91 100644 --- a/drivers/net/dsa/mt7530-mmio.c +++ b/drivers/net/dsa/mt7530-mmio.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include #include #include #include diff --git a/drivers/net/dsa/ocelot/seville_vsc9953.c b/drivers/net/dsa/ocelot/seville_vsc9953.c index eb3944ba2a72..962cf4653c36 100644 --- a/drivers/net/dsa/ocelot/seville_vsc9953.c +++ b/drivers/net/dsa/ocelot/seville_vsc9953.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 932b3a3df2e5..59001fd4b6f7 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -178,10 +178,15 @@ static void airoha_fe_maccr_init(struct airoha_eth *eth) { int p; - for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) + for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) { airoha_fe_set(eth, REG_GDM_FWD_CFG(p), GDM_TCP_CKSUM_MASK | GDM_UDP_CKSUM_MASK | GDM_IP4_CKSUM_MASK | GDM_DROP_CRC_ERR_MASK); + airoha_fe_rmw(eth, REG_GDM_LEN_CFG(p), + GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, + FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | + FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_RX_SIZE)); + } airoha_fe_rmw(eth, REG_CDM_VLAN_CTRL(1), CDM_VLAN_MASK, FIELD_PREP(CDM_VLAN_MASK, 0x8100)); @@ -944,6 +949,25 @@ static void airoha_qdma_wake_netdev_txqs(struct airoha_queue *q) q->txq_stopped = false; } +static void airoha_unmap_xmit_buf(struct airoha_eth *eth, + struct airoha_queue_entry *e) +{ + switch (e->dma_type) { + case AIROHA_DMA_MAP_PAGE: + dma_unmap_page(eth->dev, e->dma_addr, e->dma_len, + DMA_TO_DEVICE); + break; + case AIROHA_DMA_MAP_SINGLE: + dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, + DMA_TO_DEVICE); + break; + case AIROHA_DMA_UNMAPPED: + default: + break; + } + e->dma_type = AIROHA_DMA_UNMAPPED; +} + static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) { struct airoha_tx_irq_queue *irq_q; @@ -1006,9 +1030,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) skb = e->skb; e->skb = NULL; - dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, - DMA_TO_DEVICE); - e->dma_addr = 0; + airoha_unmap_xmit_buf(eth, e); list_add_tail(&e->list, &q->tx_list); WRITE_ONCE(desc->msg0, 0); @@ -1177,12 +1199,10 @@ static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma) struct airoha_qdma_desc *desc = &q->desc[j]; struct sk_buff *skb = e->skb; - if (!e->dma_addr) + if (e->dma_type == AIROHA_DMA_UNMAPPED) continue; - dma_unmap_single(qdma->eth->dev, e->dma_addr, - e->dma_len, DMA_TO_DEVICE); - e->dma_addr = 0; + airoha_unmap_xmit_buf(qdma->eth, e); list_add_tail(&e->list, &q->tx_list); WRITE_ONCE(desc->ctrl, 0); @@ -1831,13 +1851,24 @@ static void airoha_update_hw_stats(struct airoha_gdm_dev *dev) spin_unlock(&port->stats_lock); } +static void airoha_dev_set_xmit_frame_size(struct net_device *netdev) +{ + struct airoha_gdm_dev *dev = netdev_priv(netdev); + + airoha_ppe_set_xmit_frame_size(dev); + if (!airoha_is_lan_gdm_dev(dev)) + airoha_fe_rmw(dev->eth, REG_WAN_MTU0, WAN_MTU0_MASK, + FIELD_PREP(WAN_MTU0_MASK, + VLAN_ETH_HLEN + netdev->mtu)); +} + static int airoha_dev_open(struct net_device *netdev) { - int err, len = ETH_HLEN + netdev->mtu + ETH_FCS_LEN; struct airoha_gdm_dev *dev = netdev_priv(netdev); struct airoha_gdm_port *port = dev->port; - u32 cur_len, pse_port = FE_PSE_PORT_PPE1; struct airoha_qdma *qdma = dev->qdma; + u32 pse_port = FE_PSE_PORT_PPE1; + int err; netif_tx_start_all_queues(netdev); err = airoha_set_vip_for_gdm_port(dev, true); @@ -1851,19 +1882,7 @@ static int airoha_dev_open(struct net_device *netdev) airoha_fe_clear(qdma->eth, REG_GDM_INGRESS_CFG(port->id), GDM_STAG_EN_MASK); - cur_len = airoha_fe_get(qdma->eth, REG_GDM_LEN_CFG(port->id), - GDM_LONG_LEN_MASK); - if (!port->users || len > cur_len) { - /* Opening a sibling net_device with a larger MTU updates the - * MTU of already running devices. This is required to allow - * multiple net_devices with different MTUs to share the same - * GDM port. - */ - airoha_fe_rmw(qdma->eth, REG_GDM_LEN_CFG(port->id), - GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, - FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | - FIELD_PREP(GDM_LONG_LEN_MASK, len)); - } + airoha_dev_set_xmit_frame_size(netdev); port->users++; if (!airoha_is_lan_gdm_dev(dev) && @@ -1875,30 +1894,6 @@ static int airoha_dev_open(struct net_device *netdev) return 0; } -static void airoha_set_port_mtu(struct airoha_eth *eth, - struct airoha_gdm_port *port) -{ - u32 len = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(port->devs); i++) { - struct airoha_gdm_dev *dev = port->devs[i]; - struct net_device *netdev; - - if (!dev) - continue; - - netdev = netdev_from_priv(dev); - if (netif_running(netdev)) - len = max_t(u32, len, netdev->mtu); - } - len += ETH_HLEN + ETH_FCS_LEN; - - airoha_fe_rmw(eth, REG_GDM_LEN_CFG(port->id), - GDM_LONG_LEN_MASK, - FIELD_PREP(GDM_LONG_LEN_MASK, len)); -} - static int airoha_dev_stop(struct net_device *netdev) { struct airoha_gdm_dev *dev = netdev_priv(netdev); @@ -1909,7 +1904,7 @@ static int airoha_dev_stop(struct net_device *netdev) airoha_set_vip_for_gdm_port(dev, false); if (--port->users) - airoha_set_port_mtu(dev->eth, port); + airoha_ppe_set_xmit_frame_size(dev); else airoha_set_gdm_port_fwd_cfg(qdma->eth, REG_GDM_FWD_CFG(port->id), @@ -1962,10 +1957,6 @@ static int airoha_enable_gdm2_loopback(struct airoha_gdm_dev *dev) FIELD_PREP(LPBK_CHAN_MASK, chan) | LBK_GAP_MODE_MASK | LBK_LEN_MODE_MASK | LBK_CHAN_MODE_MASK | LPBK_EN_MASK); - airoha_fe_rmw(eth, REG_GDM_LEN_CFG(AIROHA_GDM2_IDX), - GDM_SHORT_LEN_MASK | GDM_LONG_LEN_MASK, - FIELD_PREP(GDM_SHORT_LEN_MASK, 60) | - FIELD_PREP(GDM_LONG_LEN_MASK, AIROHA_MAX_MTU)); /* Forward the traffic to the proper GDM port */ pse_port = port->id == AIROHA_GDM3_IDX ? FE_PSE_PORT_GDM3 : FE_PSE_PORT_GDM4; @@ -2098,7 +2089,7 @@ static int airoha_dev_change_mtu(struct net_device *netdev, int mtu) WRITE_ONCE(netdev->mtu, mtu); if (port->users) - airoha_set_port_mtu(dev->eth, port); + airoha_dev_set_xmit_frame_size(netdev); return 0; } @@ -2193,8 +2184,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, struct netdev_queue *txq; struct airoha_queue *q; LIST_HEAD(tx_list); + dma_addr_t addr; int i = 0, qid; - void *data; u16 index; u8 fport; @@ -2250,24 +2241,22 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, return NETDEV_TX_BUSY; } - len = skb_headlen(skb); - data = skb->data; - e = list_first_entry(&q->tx_list, struct airoha_queue_entry, list); + len = skb_headlen(skb); + addr = dma_map_single(netdev->dev.parent, skb->data, len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(netdev->dev.parent, addr))) + goto error_unlock; + + e->dma_type = AIROHA_DMA_MAP_SINGLE; index = e - q->entry; while (true) { struct airoha_qdma_desc *desc = &q->desc[index]; skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - dma_addr_t addr; u32 val; - addr = dma_map_single(netdev->dev.parent, data, len, - DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(netdev->dev.parent, addr))) - goto error_unmap; - list_move_tail(&e->list, &tx_list); e->skb = i == nr_frags - 1 ? skb : NULL; e->dma_addr = addr; @@ -2291,8 +2280,13 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, if (++i == nr_frags) break; - data = skb_frag_address(frag); len = skb_frag_size(frag); + addr = skb_frag_dma_map(netdev->dev.parent, frag, 0, len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(netdev->dev.parent, addr))) + goto error_unmap; + + e->dma_type = AIROHA_DMA_MAP_PAGE; } q->queued += i; @@ -2313,11 +2307,8 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, return NETDEV_TX_OK; error_unmap: - list_for_each_entry(e, &tx_list, list) { - dma_unmap_single(netdev->dev.parent, e->dma_addr, e->dma_len, - DMA_TO_DEVICE); - e->dma_addr = 0; - } + list_for_each_entry(e, &tx_list, list) + airoha_unmap_xmit_buf(dev->eth, e); list_splice(&tx_list, &q->tx_list); error_unlock: spin_unlock_bh(&q->lock); diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h index d7ff8c5200e2..f6d01a8e8da1 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h @@ -23,6 +23,7 @@ #define AIROHA_MAX_DSA_PORTS 7 #define AIROHA_MAX_NUM_RSTS 3 #define AIROHA_MAX_MTU 9220 +#define AIROHA_MAX_RX_SIZE 16128 #define AIROHA_MAX_PACKET_SIZE 2048 #define AIROHA_NUM_QOS_CHANNELS 4 #define AIROHA_NUM_QOS_QUEUES 8 @@ -170,12 +171,19 @@ enum trtcm_param { #define TRTCM_TOKEN_RATE_MASK GENMASK(23, 6) #define TRTCM_TOKEN_RATE_FRACTION_MASK GENMASK(5, 0) +enum airoha_dma_map_type { + AIROHA_DMA_UNMAPPED, + AIROHA_DMA_MAP_SINGLE, + AIROHA_DMA_MAP_PAGE, +}; + struct airoha_queue_entry { union { void *buf; struct { struct list_head list; struct sk_buff *skb; + enum airoha_dma_map_type dma_type; }; }; dma_addr_t dma_addr; @@ -676,6 +684,7 @@ int airoha_get_fe_port(struct airoha_gdm_dev *dev); bool airoha_is_valid_gdm_dev(struct airoha_eth *eth, struct airoha_gdm_dev *dev); +void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev); void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport); bool airoha_ppe_is_enabled(struct airoha_eth *eth, int index); void airoha_ppe_check_skb(struct airoha_ppe_dev *dev, struct sk_buff *skb, diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 42f4b0f21d17..e7c78293002a 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -97,6 +97,33 @@ void airoha_ppe_set_cpu_port(struct airoha_gdm_dev *dev, u8 ppe_id, u8 fport) __field_prep(DFT_CPORT_MASK(fport), fe_cpu_port)); } +void airoha_ppe_set_xmit_frame_size(struct airoha_gdm_dev *dev) +{ + struct airoha_gdm_port *port = dev->port; + struct airoha_eth *eth = dev->eth; + int i, ppe_id, index; + u32 len = 0; + + for (i = 0; i < ARRAY_SIZE(port->devs); i++) { + struct airoha_gdm_dev *d = port->devs[i]; + struct net_device *netdev; + + if (!d) + continue; + + netdev = netdev_from_priv(d); + if (netif_running(netdev)) + len = max_t(u32, len, netdev->mtu); + } + len += VLAN_ETH_HLEN; + + ppe_id = !airoha_is_lan_gdm_dev(dev) && airoha_ppe_is_enabled(eth, 1); + index = port->id == AIROHA_GDM4_IDX ? 7 : port->id; + airoha_fe_rmw(eth, REG_PPE_MTU(ppe_id, index), + FP_EGRESS_MTU_MASK(index), + __field_prep(FP_EGRESS_MTU_MASK(index), len)); +} + static void airoha_ppe_hw_init(struct airoha_ppe *ppe) { u32 sram_ppe_num_data_entries = PPE_SRAM_NUM_ENTRIES, sram_num_entries; @@ -115,8 +142,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) PPE_RAM_NUM_ENTRIES_SHIFT(sram_ppe_num_data_entries); for (i = 0; i < eth->soc->num_ppe; i++) { - int p; - airoha_fe_wr(eth, REG_PPE_TB_BASE(i), ppe->foe_dma + sram_tb_size); @@ -166,15 +191,6 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) airoha_fe_wr(eth, REG_PPE_HASH_SEED(i), PPE_HASH_SEED); airoha_fe_clear(eth, REG_PPE_PPE_FLOW_CFG(i), PPE_FLOW_CFG_IP6_6RD_MASK); - - for (p = 0; p < ARRAY_SIZE(eth->ports); p++) - airoha_fe_rmw(eth, REG_PPE_MTU(i, p), - FP0_EGRESS_MTU_MASK | - FP1_EGRESS_MTU_MASK, - FIELD_PREP(FP0_EGRESS_MTU_MASK, - AIROHA_MAX_MTU) | - FIELD_PREP(FP1_EGRESS_MTU_MASK, - AIROHA_MAX_MTU)); } for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { @@ -196,6 +212,7 @@ static void airoha_ppe_hw_init(struct airoha_ppe *ppe) airoha_ppe_is_enabled(eth, 1); fport = airoha_get_fe_port(dev); airoha_ppe_set_cpu_port(dev, ppe_id, fport); + airoha_ppe_set_xmit_frame_size(dev); } } } diff --git a/drivers/net/ethernet/airoha/airoha_regs.h b/drivers/net/ethernet/airoha/airoha_regs.h index 436f3c8779c1..6fed63d013b4 100644 --- a/drivers/net/ethernet/airoha/airoha_regs.h +++ b/drivers/net/ethernet/airoha/airoha_regs.h @@ -327,9 +327,8 @@ #define PPE_SRAM_TABLE_EN_MASK BIT(0) #define REG_PPE_MTU_BASE(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x304) -#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + ((_n) << 2)) -#define FP1_EGRESS_MTU_MASK GENMASK(29, 16) -#define FP0_EGRESS_MTU_MASK GENMASK(13, 0) +#define REG_PPE_MTU(_m, _n) (REG_PPE_MTU_BASE(_m) + (((_n) / 2) << 2)) +#define FP_EGRESS_MTU_MASK(_n) GENMASK(13 + (((_n) % 2) << 4), ((_n) % 2) << 4) #define REG_PPE_RAM_CTRL(_n) (((_n) ? PPE2_BASE : PPE1_BASE) + 0x31c) #define PPE_SRAM_CTRL_ACK_MASK BIT(31) @@ -377,6 +376,10 @@ #define REG_SRC_PORT_FC_MAP6 0x2298 #define FC_ID_OF_SRC_PORT_MASK(_n) GENMASK(4 + ((_n) << 3), ((_n) << 3)) +#define REG_WAN_MTU0 0x2300 +#define WAN_MTU1_MASK GENMASK(29, 16) +#define WAN_MTU0_MASK GENMASK(13, 0) + #define REG_CDM5_RX_OQ1_DROP_CNT 0x29d4 /* QDMA */ diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c index ef5174eb01ec..a2410fba6be2 100644 --- a/drivers/net/ethernet/calxeda/xgmac.c +++ b/drivers/net/ethernet/calxeda/xgmac.c @@ -3,7 +3,6 @@ * Copyright 2010-2011 Calxeda, Inc. */ #include -#include #include #include #include diff --git a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c index 75f22f74774c..06b4424e778e 100644 --- a/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c +++ b/drivers/net/ethernet/cavium/liquidio/cn23xx_pf_device.c @@ -1163,18 +1163,14 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct) if (octeon_map_pci_barx(oct, 1, MAX_BAR1_IOREMAP_SIZE)) { dev_err(&oct->pci_dev->dev, "%s CN23XX BAR1 map failed\n", __func__); - octeon_unmap_pci_barx(oct, 0); - return 1; + goto err_unmap_bar0; } if (cn23xx_get_pf_num(oct) != 0) - return 1; + goto err_unmap_bar1; - if (cn23xx_sriov_config(oct)) { - octeon_unmap_pci_barx(oct, 0); - octeon_unmap_pci_barx(oct, 1); - return 1; - } + if (cn23xx_sriov_config(oct)) + goto err_unmap_bar1; octeon_write_csr64(oct, CN23XX_SLI_MAC_CREDIT_CNT, 0x3F802080802080ULL); @@ -1205,6 +1201,12 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct) oct->coproc_clock_rate = 1000000ULL * cn23xx_coprocessor_clock(oct); return 0; + +err_unmap_bar1: + octeon_unmap_pci_barx(oct, 1); +err_unmap_bar0: + octeon_unmap_pci_barx(oct, 0); + return 1; } EXPORT_SYMBOL_GPL(setup_cn23xx_octeon_pf_device); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 171750fad44f..6871127427fa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -6737,14 +6737,6 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state) return; } - if (is_t4(adapter->params.chip)) { - sge_idma_decode = (const char **)t4_decode; - sge_idma_decode_nstates = ARRAY_SIZE(t4_decode); - } else { - sge_idma_decode = (const char **)t5_decode; - sge_idma_decode_nstates = ARRAY_SIZE(t5_decode); - } - if (state < sge_idma_decode_nstates) CH_WARN(adapter, "idma state %s\n", sge_idma_decode[state]); else diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 5cb478e98697..6d4fbadc7dcf 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include "nps_enet.h" diff --git a/drivers/net/ethernet/faraday/ftmac100.c b/drivers/net/ethernet/faraday/ftmac100.c index 5803a382f0ba..40ba001d4b3f 100644 --- a/drivers/net/ethernet/faraday/ftmac100.c +++ b/drivers/net/ethernet/faraday/ftmac100.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 3edc8d142dd5..ad2d8256eb8d 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -7,7 +7,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index aa8a87124b10..8e3f345dd9aa 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -1783,6 +1783,7 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, { struct enetc_tx_swbd xdp_redirect_arr[ENETC_MAX_SKB_FRAGS] = {0}; struct enetc_ndev_priv *priv = netdev_priv(ndev); + struct skb_shared_info *shinfo; struct enetc_bdr *tx_ring; int xdp_tx_bd_cnt, i, k; int xdp_tx_frm_cnt = 0; @@ -1798,6 +1799,12 @@ int enetc_xdp_xmit(struct net_device *ndev, int num_frames, prefetchw(ENETC_TXBD(*tx_ring, tx_ring->next_to_use)); for (k = 0; k < num_frames; k++) { + if (xdp_frame_has_frags(frames[k])) { + shinfo = xdp_get_shared_info_from_frame(frames[k]); + if (unlikely((shinfo->nr_frags + 1) > ENETC_MAX_SKB_FRAGS)) + break; + } + xdp_tx_bd_cnt = enetc_xdp_frame_to_xdp_tx_swbd(tx_ring, xdp_redirect_arr, frames[k]); diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c index d39617ab9306..f0600b97a3d6 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ierb.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ierb.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 013273a2de32..299bab043175 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -1995,8 +1995,10 @@ static int fman_init(struct fman *fman) /* Init KeyGen */ fman->keygen = keygen_init(fman->kg_regs); - if (!fman->keygen) + if (!fman->keygen) { + free_init_resources(fman); return -EINVAL; + } err = enable(fman, cfg); if (err != 0) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 3271de5844f8..89215e1ddc2d 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -469,10 +469,13 @@ static void free_gfar_dev(struct gfar_private *priv) { int i, j; - for (i = 0; i < priv->num_grps; i++) + for (i = 0; i < MAXGROUPS; i++) for (j = 0; j < GFAR_NUM_IRQS; j++) { - kfree(priv->gfargrp[i].irqinfo[j]); - priv->gfargrp[i].irqinfo[j] = NULL; + if (priv->gfargrp[i].irqinfo[j]) { + irq_dispose_mapping(priv->gfargrp[i].irqinfo[j]->irq); + kfree(priv->gfargrp[i].irqinfo[j]); + priv->gfargrp[i].irqinfo[j] = NULL; + } } free_netdev(priv->ndev); @@ -616,7 +619,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev) static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) { const char *model; - int err = 0, i; + int err = 0, i, j; phy_interface_t interface; struct net_device *dev = NULL; struct gfar_private *priv = NULL; @@ -702,8 +705,11 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv->rx_list.count = 0; mutex_init(&priv->rx_queue_access); - for (i = 0; i < MAXGROUPS; i++) + for (i = 0; i < MAXGROUPS; i++) { priv->gfargrp[i].regs = NULL; + for (j = 0; j < GFAR_NUM_IRQS; j++) + priv->gfargrp[i].irqinfo[j] = NULL; + } /* Parse and initialize group specific information */ if (priv->mode == MQ_MG_MODE) { diff --git a/drivers/net/ethernet/ibm/emac/tah.c b/drivers/net/ethernet/ibm/emac/tah.c index 09f6373ed2f9..ed07532aaf85 100644 --- a/drivers/net/ethernet/ibm/emac/tah.c +++ b/drivers/net/ethernet/ibm/emac/tah.c @@ -14,7 +14,6 @@ * * Copyright (c) 2005 Eugene Surovegin */ -#include #include #include #include diff --git a/drivers/net/ethernet/ibm/emac/zmii.c b/drivers/net/ethernet/ibm/emac/zmii.c index 69ca6065de1c..a3839cf02ec4 100644 --- a/drivers/net/ethernet/ibm/emac/zmii.c +++ b/drivers/net/ethernet/ibm/emac/zmii.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/marvell/mvmdio.c b/drivers/net/ethernet/marvell/mvmdio.c index 3f4447e68888..2ccb8c8f5feb 100644 --- a/drivers/net/ethernet/marvell/mvmdio.c +++ b/drivers/net/ethernet/marvell/mvmdio.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c index 71b3a059c964..daff53ba7d09 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c @@ -714,6 +714,26 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx) } sc_xarray_element->rx_sc = rx_sc; + + rx_sc->md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL); + if (!rx_sc->md_dst) { + err = -ENOMEM; + goto destroy_sc_xarray_elemenet; + } + + rx_sc->sci = ctx_rx_sc->sci; + rx_sc->active = ctx_rx_sc->active; + rx_sc->sc_xarray_element = sc_xarray_element; + rx_sc->md_dst->u.macsec_info.sci = rx_sc->sci; + + /* + * Publish the fully-initialised SC last: xa_alloc() makes + * sc_xarray_element->rx_sc (and rx_sc->md_dst) reachable from the RX + * datapath via xa_load(). Doing it only after md_dst is allocated and + * initialised pairs with the rcu_read_lock()/xa_load() in + * mlx5e_macsec_offload_handle_rx_skb(), so a reader can never observe + * a non-NULL md_dst with uninitialised contents. + */ err = xa_alloc(&macsec->sc_xarray, &sc_xarray_element->fs_id, sc_xarray_element, XA_LIMIT(1, MLX5_MACEC_RX_FS_ID_MAX), GFP_KERNEL); if (err) { @@ -721,27 +741,16 @@ static int mlx5e_macsec_add_rxsc(struct macsec_context *ctx) netdev_err(ctx->netdev, "MACsec offload: unable to create entry for RX SC (%d Rx SCs already allocated)\n", MLX5_MACEC_RX_FS_ID_MAX); - goto destroy_sc_xarray_elemenet; + goto destroy_md_dst; } - rx_sc->md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL); - if (!rx_sc->md_dst) { - err = -ENOMEM; - goto erase_xa_alloc; - } - - rx_sc->sci = ctx_rx_sc->sci; - rx_sc->active = ctx_rx_sc->active; list_add_rcu(&rx_sc->rx_sc_list_element, rx_sc_list); - - rx_sc->sc_xarray_element = sc_xarray_element; - rx_sc->md_dst->u.macsec_info.sci = rx_sc->sci; mutex_unlock(&macsec->lock); return 0; -erase_xa_alloc: - xa_erase(&macsec->sc_xarray, sc_xarray_element->fs_id); +destroy_md_dst: + dst_release(&rx_sc->md_dst->dst); destroy_sc_xarray_elemenet: kfree(sc_xarray_element); destroy_rx_sc: @@ -829,7 +838,7 @@ static void macsec_del_rxsc_ctx(struct mlx5e_macsec *macsec, struct mlx5e_macsec */ list_del_rcu(&rx_sc->rx_sc_list_element); xa_erase(&macsec->sc_xarray, rx_sc->sc_xarray_element->fs_id); - metadata_dst_free(rx_sc->md_dst); + dst_release(&rx_sc->md_dst->dst); kfree(rx_sc->sc_xarray_element); kfree_rcu_mightsleep(rx_sc); } @@ -1695,10 +1704,10 @@ void mlx5e_macsec_offload_handle_rx_skb(struct net_device *netdev, rcu_read_lock(); sc_xarray_element = xa_load(&macsec->sc_xarray, fs_id); - rx_sc = sc_xarray_element->rx_sc; - if (rx_sc) { - dst_hold(&rx_sc->md_dst->dst); - skb_dst_set(skb, &rx_sc->md_dst->dst); + rx_sc = sc_xarray_element ? sc_xarray_element->rx_sc : NULL; + if (rx_sc && rx_sc->md_dst) { + if (dst_hold_safe(&rx_sc->md_dst->dst)) + skb_dst_set(skb, &rx_sc->md_dst->dst); } rcu_read_unlock(); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c index eae02bc74221..3bcf412a08c4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c @@ -205,6 +205,7 @@ static int hws_bwc_matcher_move(struct mlx5hws_bwc_matcher *bwc_matcher) ret = mlx5hws_matcher_resize_set_target(old_matcher, new_matcher); if (ret) { mlx5hws_err(ctx, "Rehash error: failed setting resize target\n"); + mlx5hws_matcher_destroy(new_matcher); return ret; } diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 654190263535..02c3c2204f18 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c index f9f565c1036d..60a50222f33a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c +++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c index 1fee57054b20..80f1b8d7b326 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c +++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include "core.h" diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 9cd85a0d0c3a..401f8b8ae1ca 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -194,16 +194,18 @@ static bool fbnic_tx_tstamp(struct sk_buff *skb) static bool fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb, - struct skb_shared_info *shinfo, __le64 *meta, - unsigned int *l2len, unsigned int *i3len) + __le64 *meta, unsigned int *l2len, unsigned int *i3len) { unsigned int l3_type, l4_type, l4len, hdrlen; + struct skb_shared_info *shinfo; unsigned char *l4hdr; __be16 payload_len; if (unlikely(skb_cow_head(skb, 0))) return true; + shinfo = skb_shinfo(skb); + if (shinfo->gso_type & SKB_GSO_PARTIAL) { l3_type = FBNIC_TWD_L3_TYPE_OTHER; } else if (!skb->encapsulation) { @@ -258,7 +260,6 @@ fbnic_tx_lso(struct fbnic_ring *ring, struct sk_buff *skb, static bool fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) { - struct skb_shared_info *shinfo = skb_shinfo(skb); unsigned int l2len, i3len; if (fbnic_tx_tstamp(skb)) @@ -273,8 +274,8 @@ fbnic_tx_offloads(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) *meta |= cpu_to_le64(FIELD_PREP(FBNIC_TWD_CSUM_OFFSET_MASK, skb->csum_offset / 2)); - if (shinfo->gso_size) { - if (fbnic_tx_lso(ring, skb, shinfo, meta, &l2len, &i3len)) + if (skb_is_gso(skb)) { + if (fbnic_tx_lso(ring, skb, meta, &l2len, &i3len)) return true; } else { *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_CSO); diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 1cdce35e1423..e759171bfd76 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -3541,8 +3541,8 @@ static int lan743x_hardware_init(struct lan743x_adapter *adapter, adapter->max_tx_channels = PCI11X1X_MAX_TX_CHANNELS; adapter->used_tx_channels = PCI11X1X_USED_TX_CHANNELS; adapter->max_vector_count = PCI11X1X_MAX_VECTOR_COUNT; - pci11x1x_strap_get_status(adapter); spin_lock_init(&adapter->eth_syslock_spinlock); + pci11x1x_strap_get_status(adapter); mutex_init(&adapter->sgmii_rw_lock); pci11x1x_set_rfe_rd_fifo_threshold(adapter); sgmii_ctl = lan743x_csr_read(adapter, SGMII_CTL); diff --git a/drivers/net/ethernet/qlogic/qede/qede_fp.c b/drivers/net/ethernet/qlogic/qede/qede_fp.c index e338bfc8b7b2..33e18bb69774 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_fp.c +++ b/drivers/net/ethernet/qlogic/qede/qede_fp.c @@ -961,7 +961,7 @@ static inline void qede_tpa_cont(struct qede_dev *edev, { int i; - for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++) + for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++) qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index, le16_to_cpu(cqe->len_list[i])); @@ -986,7 +986,7 @@ static int qede_tpa_end(struct qede_dev *edev, dma_unmap_page(rxq->dev, tpa_info->buffer.mapping, PAGE_SIZE, rxq->data_direction); - for (i = 0; cqe->len_list[i] && i < ARRAY_SIZE(cqe->len_list); i++) + for (i = 0; i < ARRAY_SIZE(cqe->len_list) && cqe->len_list[i]; i++) qede_fill_frag_skb(edev, rxq, cqe->tpa_agg_index, le16_to_cpu(cqe->len_list[i])); if (unlikely(i > 1)) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-nuvoton.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-nuvoton.c index 2ab6ecac6422..b027cdf6afc2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-nuvoton.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-nuvoton.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c index 44d4ceb8415f..e02ad3762b5f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include "stmmac_platform.h" diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c index 322bdf167a4a..62d8ac538679 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index b1ea248e3311..4ee5b5fe1fa7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -7,7 +7,6 @@ * */ -#include #include #include #include diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index d042567b8128..814d88d2aee4 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1802,6 +1802,7 @@ static bool wx_set_vmdq_queues(struct wx *wx) rss_i = 4; } } else { + vmdq_m = WX_VMDQ_1Q_MASK; /* double check we are limited to maximum pools */ vmdq_i = min_t(u16, 8, vmdq_i); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index c7befe4cdfe9..65e3e55db1cf 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -486,6 +486,7 @@ enum WX_MSCA_CMD_value { #define WX_VMDQ_4Q_MASK 0x7C #define WX_VMDQ_2Q_MASK 0x7E +#define WX_VMDQ_1Q_MASK 0x7F /****************** Manageablility Host Interface defines ********************/ #define WX_HI_MAX_BLOCK_BYTE_LENGTH 256 /* Num of bytes in range */ diff --git a/drivers/net/ethernet/xscale/ptp_ixp46x.c b/drivers/net/ethernet/xscale/ptp_ixp46x.c index 93c64db22a69..558c4f8d23f7 100644 --- a/drivers/net/ethernet/xscale/ptp_ixp46x.c +++ b/drivers/net/ethernet/xscale/ptp_ixp46x.c @@ -6,7 +6,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index d3f42efc5d1a..05a65a9659ad 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c index 2f0ccdd937cc..331c00ad02c0 100644 --- a/drivers/net/ipa/ipa_smp2p.c +++ b/drivers/net/ipa/ipa_smp2p.c @@ -232,19 +232,27 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init) &valid_bit); if (IS_ERR(valid_state)) return PTR_ERR(valid_state); - if (valid_bit >= 32) /* BITS_PER_U32 */ - return -EINVAL; + if (valid_bit >= 32) { /* BITS_PER_U32 */ + ret = -EINVAL; + goto err_valid_state_put; + } enabled_state = qcom_smem_state_get(dev, "ipa-clock-enabled", &enabled_bit); - if (IS_ERR(enabled_state)) - return PTR_ERR(enabled_state); - if (enabled_bit >= 32) /* BITS_PER_U32 */ - return -EINVAL; + if (IS_ERR(enabled_state)) { + ret = PTR_ERR(enabled_state); + goto err_valid_state_put; + } + if (enabled_bit >= 32) { /* BITS_PER_U32 */ + ret = -EINVAL; + goto err_enabled_state_put; + } smp2p = kzalloc_obj(*smp2p); - if (!smp2p) - return -ENOMEM; + if (!smp2p) { + ret = -ENOMEM; + goto err_enabled_state_put; + } smp2p->ipa = ipa; @@ -289,6 +297,10 @@ ipa_smp2p_init(struct ipa *ipa, struct platform_device *pdev, bool modem_init) ipa->smp2p = NULL; mutex_destroy(&smp2p->mutex); kfree(smp2p); +err_enabled_state_put: + qcom_smem_state_put(enabled_state); +err_valid_state_put: + qcom_smem_state_put(valid_state); return ret; } @@ -305,6 +317,8 @@ void ipa_smp2p_exit(struct ipa *ipa) ipa_smp2p_power_release(ipa); ipa->smp2p = NULL; mutex_destroy(&smp2p->mutex); + qcom_smem_state_put(smp2p->enabled_state); + qcom_smem_state_put(smp2p->valid_state); kfree(smp2p); } diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c index b88f63234b4e..ed20352a589a 100644 --- a/drivers/net/mdio/mdio-i2c.c +++ b/drivers/net/mdio/mdio-i2c.c @@ -419,50 +419,6 @@ static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int devad, return 0; } -static int i2c_mii_probe_rollball(struct i2c_adapter *i2c) -{ - u8 data_buf[] = { ROLLBALL_DATA_ADDR, 0x01, 0x00, 0x00 }; - u8 cmd_buf[] = { ROLLBALL_CMD_ADDR, ROLLBALL_CMD_READ }; - u8 cmd_addr = ROLLBALL_CMD_ADDR; - struct i2c_msg msgs[2]; - u8 result; - int ret; - int i; - - msgs[0].addr = ROLLBALL_PHY_I2C_ADDR; - msgs[0].flags = 0; - msgs[0].len = sizeof(data_buf); - msgs[0].buf = data_buf; - msgs[1].addr = ROLLBALL_PHY_I2C_ADDR; - msgs[1].flags = 0; - msgs[1].len = sizeof(cmd_buf); - msgs[1].buf = cmd_buf; - - ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - return -ENODEV; - - msgs[0].addr = ROLLBALL_PHY_I2C_ADDR; - msgs[0].flags = 0; - msgs[0].len = 1; - msgs[0].buf = &cmd_addr; - msgs[1].addr = ROLLBALL_PHY_I2C_ADDR; - msgs[1].flags = I2C_M_RD; - msgs[1].len = 1; - msgs[1].buf = &result; - - for (i = 0; i < 10; i++) { - msleep(20); - ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - return -ENODEV; - if (result == ROLLBALL_CMD_DONE) - return 0; - } - - return -ENODEV; -} - static int i2c_mii_init_rollball(struct i2c_adapter *i2c) { struct i2c_msg msg; @@ -482,11 +438,11 @@ static int i2c_mii_init_rollball(struct i2c_adapter *i2c) ret = i2c_transfer(i2c, &msg, 1); if (ret < 0) - return -ENODEV; - if (ret != 1) + return ret; + else if (ret != 1) return -EIO; - - return i2c_mii_probe_rollball(i2c); + else + return 0; } static bool mdio_i2c_check_functionality(struct i2c_adapter *i2c, @@ -531,10 +487,9 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, case MDIO_I2C_ROLLBALL: ret = i2c_mii_init_rollball(i2c); if (ret < 0) { - if (ret != -ENODEV) - dev_err(parent, - "Cannot initialize RollBall MDIO I2C protocol: %d\n", - ret); + dev_err(parent, + "Cannot initialize RollBall MDIO I2C protocol: %d\n", + ret); mdiobus_free(mii); return ERR_PTR(ret); } diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 892ed3780a65..afd52a1cd7f8 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/mhi_net.c b/drivers/net/mhi_net.c index ae169929a9d8..5eb6b461f50b 100644 --- a/drivers/net/mhi_net.c +++ b/drivers/net/mhi_net.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/net/netdevsim/ethtool.c b/drivers/net/netdevsim/ethtool.c index 9350ba48eb81..025ea79879f3 100644 --- a/drivers/net/netdevsim/ethtool.c +++ b/drivers/net/netdevsim/ethtool.c @@ -252,6 +252,7 @@ void nsim_ethtool_init(struct netdevsim *ns) ns->ethtool.channels = ns->nsim_bus_dev->num_queues; ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir); + ns->ethtool_ddir = ethtool; debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err); debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err); @@ -272,3 +273,8 @@ void nsim_ethtool_init(struct netdevsim *ns) debugfs_create_u32("tx_max_pending", 0600, dir, &ns->ethtool.ring.tx_max_pending); } + +void nsim_ethtool_fini(struct netdevsim *ns) +{ + debugfs_remove(ns->ethtool_ddir); +} diff --git a/drivers/net/netdevsim/netdev.c b/drivers/net/netdevsim/netdev.c index 27e5f109f933..4e9d7e10b527 100644 --- a/drivers/net/netdevsim/netdev.c +++ b/drivers/net/netdevsim/netdev.c @@ -1165,6 +1165,7 @@ struct netdevsim *nsim_create(struct nsim_dev *nsim_dev, return ns; err_free_netdev: + nsim_ethtool_fini(ns); free_netdev(dev); return ERR_PTR(err); } @@ -1178,6 +1179,7 @@ void nsim_destroy(struct netdevsim *ns) debugfs_remove(ns->vlan_dfs); debugfs_remove(ns->qr_dfs); debugfs_remove(ns->pp_dfs); + nsim_ethtool_fini(ns); if (ns->nb.notifier_call) unregister_netdevice_notifier_dev_net(ns->netdev, &ns->nb, diff --git a/drivers/net/netdevsim/netdevsim.h b/drivers/net/netdevsim/netdevsim.h index 4c9cc96dcec3..64f77f93d937 100644 --- a/drivers/net/netdevsim/netdevsim.h +++ b/drivers/net/netdevsim/netdevsim.h @@ -154,6 +154,7 @@ struct netdevsim { struct dentry *pp_dfs; struct dentry *qr_dfs; struct dentry *vlan_dfs; + struct dentry *ethtool_ddir; struct nsim_ethtool ethtool; struct netdevsim __rcu *peer; @@ -169,6 +170,7 @@ void nsim_destroy(struct netdevsim *ns); bool netdev_is_nsim(struct net_device *dev); void nsim_ethtool_init(struct netdevsim *ns); +void nsim_ethtool_fini(struct netdevsim *ns); void nsim_udp_tunnels_debugfs_create(struct nsim_dev *nsim_dev); int nsim_udp_tunnels_info_create(struct nsim_dev *nsim_dev, diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 03bfd8640db9..f520206734da 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -597,7 +597,6 @@ static const struct sfp_quirk sfp_quirks[] = { // OEM SFP-GE-T is a 1000Base-T module with broken TX_FAULT indicator SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault), - SFP_QUIRK_F("OEM", "SFP-10G-T-I", sfp_fixup_rollball), SFP_QUIRK_F("OEM", "SFP-10G-T", sfp_fixup_rollball_cc), SFP_QUIRK_S("OEM", "SFP-2.5G-T", sfp_quirk_oem_2_5g), SFP_QUIRK_S("OEM", "SFP-2.5G-BX10-D", sfp_quirk_2500basex), @@ -963,6 +962,7 @@ static int sfp_i2c_mdiobus_create(struct sfp *sfp) static void sfp_i2c_mdiobus_destroy(struct sfp *sfp) { mdiobus_unregister(sfp->i2c_mii); + mdiobus_free(sfp->i2c_mii); sfp->i2c_mii = NULL; } @@ -2173,17 +2173,10 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn) static int sfp_sm_add_mdio_bus(struct sfp *sfp) { - int ret; + if (sfp->mdio_protocol != MDIO_I2C_NONE) + return sfp_i2c_mdiobus_create(sfp); - if (sfp->mdio_protocol == MDIO_I2C_NONE) - return 0; - - ret = sfp_i2c_mdiobus_create(sfp); - if (ret == -ENODEV) { - sfp->mdio_protocol = MDIO_I2C_NONE; - return 0; - } - return ret; + return 0; } /* Probe a SFP for a PHY device if the module supports copper - the PHY diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c index 69dbdbde9d71..a5e6d7b26b9f 100644 --- a/drivers/net/pse-pd/pse_core.c +++ b/drivers/net/pse-pd/pse_core.c @@ -1367,7 +1367,7 @@ static void __pse_control_release(struct kref *kref) if (psec->pcdev->pi[psec->id].admin_state_enabled) regulator_disable(psec->ps); - devm_regulator_put(psec->ps); + regulator_put(psec->ps); module_put(psec->pcdev->owner); @@ -1436,8 +1436,8 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index, goto free_psec; pcdev->pi[index].admin_state_enabled = ret; - psec->ps = devm_regulator_get_exclusive(pcdev->dev, - rdev_get_name(pcdev->pi[index].rdev)); + psec->ps = regulator_get_exclusive(pcdev->dev, + rdev_get_name(pcdev->pi[index].rdev)); if (IS_ERR(psec->ps)) { ret = PTR_ERR(psec->ps); goto put_module; diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index 0bfa37c14059..09afd137b64e 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -104,6 +104,9 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 0; } + if (!skb_pull(skb, size + 4)) + return 0; + // allocate the skb for the individual packet gl_skb = alloc_skb(size, GFP_ATOMIC); if (gl_skb) { @@ -116,9 +119,6 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) // advance to the next packet packet = (struct gl_packet *)&packet->packet_data[size]; count--; - - // shift the data pointer to the next gl_packet - skb_pull(skb, size + 4); } // skip the packet length field 4 bytes diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 26afa6341d16..3e2a5876c6c8 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -3011,6 +3011,9 @@ static int virtnet_poll(struct napi_struct *napi, int budget) unsigned int xdp_xmit = 0; bool napi_complete; + if (budget) + virtqueue_disable_cb(rq->vq); + virtnet_poll_cleantx(rq, budget); received = virtnet_receive(rq, budget, &xdp_xmit); diff --git a/drivers/net/wan/fsl_qmc_hdlc.c b/drivers/net/wan/fsl_qmc_hdlc.c index 8976dea8e17e..e74f87940c4f 100644 --- a/drivers/net/wan/fsl_qmc_hdlc.c +++ b/drivers/net/wan/fsl_qmc_hdlc.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 802e6596a6a8..a7d0415b2a0e 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -16,7 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c index abe7f6501e5e..1eb69bd33a75 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/dmi.c @@ -4,7 +4,6 @@ */ #include -#include #include "core.h" #include "common.h" #include "brcm_hw_ids.h" diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index d18be2545028..ecb545793d63 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/wireless/ti/wl1251/sdio.c b/drivers/net/wireless/ti/wl1251/sdio.c index 8fdc7430c008..26a0e67de302 100644 --- a/drivers/net/wireless/ti/wl1251/sdio.c +++ b/drivers/net/wireless/ti/wl1251/sdio.c @@ -8,7 +8,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 30a1da72eb08..920864948197 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 4be1110bac88..d087d9c72f91 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c index bff46f7ca59f..0bbd41263cc2 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c +++ b/drivers/net/wwan/iosm/iosm_ipc_mux_codec.c @@ -553,19 +553,21 @@ static int mux_dl_process_dg(struct iosm_mux *ipc_mux, struct mux_adbh *adbh, u32 packet_offset, i, rc, dg_len; for (i = 0; i < nr_of_dg; i++, dg++) { - if (le32_to_cpu(dg->datagram_index) - < sizeof(struct mux_adbh)) + u32 dg_index = le32_to_cpu(dg->datagram_index); + + dg_len = le16_to_cpu(dg->datagram_length); + + if (dg_index < sizeof(struct mux_adbh)) goto dg_error; - /* Is the packet inside of the ADB */ - if (le32_to_cpu(dg->datagram_index) >= - le32_to_cpu(adbh->block_length)) { + /* Is the packet inside of the ADB and the received skb ? */ + if (dg_index >= le32_to_cpu(adbh->block_length) || + dg_index >= skb->len || + dg_len > skb->len - dg_index || + dl_head_pad_len >= dg_len) { goto dg_error; } else { - packet_offset = - le32_to_cpu(dg->datagram_index) + - dl_head_pad_len; - dg_len = le16_to_cpu(dg->datagram_length); + packet_offset = dg_index + dl_head_pad_len; /* Pass the packet to the netif layer. */ rc = ipc_mux_net_receive(ipc_mux, if_id, ipc_mux->wwan, packet_offset, @@ -589,12 +591,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux, struct mux_adbh *adbh; struct mux_adth *adth; int nr_of_dg, if_id; - u32 adth_index; + u32 adth_index, prev_index = 0; u8 *block; block = skb->data; adbh = (struct mux_adbh *)block; + /* The block header itself must fit in the received skb. */ + if (skb->len < sizeof(struct mux_adbh)) + goto adb_decode_err; + /* Process the aggregated datagram tables. */ adth_index = le32_to_cpu(adbh->first_table_index); @@ -606,6 +612,16 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux, /* Loop through mixed session tables. */ while (adth_index) { + /* The table header must lie within the received skb, and the + * chain must move forward so a modem cannot make the loop + * cycle between two tables. + */ + if (adth_index <= prev_index || + adth_index < sizeof(struct mux_adbh) || + adth_index > skb->len - sizeof(struct mux_adth)) + goto adb_decode_err; + prev_index = adth_index; + /* Get the reference to the table header. */ adth = (struct mux_adth *)(block + adth_index); @@ -629,6 +645,10 @@ static void mux_dl_adb_decode(struct iosm_mux *ipc_mux, if (le16_to_cpu(adth->table_length) < sizeof(struct mux_adth)) goto adb_decode_err; + /* The whole datagram table must fit in the received skb. */ + if (le16_to_cpu(adth->table_length) > skb->len - adth_index) + goto adb_decode_err; + /* Calculate the number of datagrams. */ nr_of_dg = (le16_to_cpu(adth->table_length) - sizeof(struct mux_adth)) / diff --git a/drivers/net/wwan/mhi_wwan_ctrl.c b/drivers/net/wwan/mhi_wwan_ctrl.c index fa73861db6ad..a31d8540fbb8 100644 --- a/drivers/net/wwan/mhi_wwan_ctrl.c +++ b/drivers/net/wwan/mhi_wwan_ctrl.c @@ -2,7 +2,6 @@ /* Copyright (c) 2021, Linaro Ltd */ #include #include -#include #include #include diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c index 1d7e3ad900c1..a94998712597 100644 --- a/drivers/net/wwan/mhi_wwan_mbim.c +++ b/drivers/net/wwan/mhi_wwan_mbim.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wwan/qcom_bam_dmux.c b/drivers/net/wwan/qcom_bam_dmux.c index 6a5b22589af4..cc6ace8d6437 100644 --- a/drivers/net/wwan/qcom_bam_dmux.c +++ b/drivers/net/wwan/qcom_bam_dmux.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/net/wwan/rpmsg_wwan_ctrl.c b/drivers/net/wwan/rpmsg_wwan_ctrl.c index 26756ff0e44d..ba17b5ae6bdb 100644 --- a/drivers/net/wwan/rpmsg_wwan_ctrl.c +++ b/drivers/net/wwan/rpmsg_wwan_ctrl.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2021, Stephan Gerhold */ #include -#include #include #include #include diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c index e2a77a5fc887..c256ae92d6b1 100644 --- a/drivers/nfc/microread/mei.c +++ b/drivers/nfc/microread/mei.c @@ -8,7 +8,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c index c493f2dbd0e2..3d3755cfa71e 100644 --- a/drivers/nfc/pn544/mei.c +++ b/drivers/nfc/pn544/mei.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/nfc/s3fwrn5/uart.c b/drivers/nfc/s3fwrn5/uart.c index 540a4ddb0b05..e17c599a2da5 100644 --- a/drivers/nfc/s3fwrn5/uart.c +++ b/drivers/nfc/s3fwrn5/uart.c @@ -10,7 +10,6 @@ #include #include -#include #include #include #include diff --git a/drivers/nvmem/an8855-efuse.c b/drivers/nvmem/an8855-efuse.c index d1afde6f623f..ed0840f7954f 100644 --- a/drivers/nvmem/an8855-efuse.c +++ b/drivers/nvmem/an8855-efuse.c @@ -3,7 +3,6 @@ * Airoha AN8855 Switch EFUSE Driver */ -#include #include #include #include diff --git a/drivers/nvmem/apple-efuses.c b/drivers/nvmem/apple-efuses.c index 1d1bf84a099f..9913e77b8ff0 100644 --- a/drivers/nvmem/apple-efuses.c +++ b/drivers/nvmem/apple-efuses.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/nvmem/brcm_nvram.c b/drivers/nvmem/brcm_nvram.c index 2dce6a7b8039..aaa6537798bf 100644 --- a/drivers/nvmem/brcm_nvram.c +++ b/drivers/nvmem/brcm_nvram.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/nvmem/layerscape-sfp.c b/drivers/nvmem/layerscape-sfp.c index e2b424561949..c1521afd5b43 100644 --- a/drivers/nvmem/layerscape-sfp.c +++ b/drivers/nvmem/layerscape-sfp.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c index aa43f5f612f9..504155e30bab 100644 --- a/drivers/nvmem/lpc18xx_eeprom.c +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/nvmem/max77759-nvmem.c b/drivers/nvmem/max77759-nvmem.c index c9961ad0e232..283000ec3a2c 100644 --- a/drivers/nvmem/max77759-nvmem.c +++ b/drivers/nvmem/max77759-nvmem.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/nvmem/mtk-efuse.c b/drivers/nvmem/mtk-efuse.c index af953e1d9230..00a84ea963a8 100644 --- a/drivers/nvmem/mtk-efuse.c +++ b/drivers/nvmem/mtk-efuse.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/nvmem/nintendo-otp.c b/drivers/nvmem/nintendo-otp.c index 355e7f1fc6d5..4440d4e5fb83 100644 --- a/drivers/nvmem/nintendo-otp.c +++ b/drivers/nvmem/nintendo-otp.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index a872c640b8c5..1de3435df116 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/nvmem/qoriq-efuse.c b/drivers/nvmem/qoriq-efuse.c index e7fd04d6dd94..80f514939ae6 100644 --- a/drivers/nvmem/qoriq-efuse.c +++ b/drivers/nvmem/qoriq-efuse.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/nvmem/rcar-efuse.c b/drivers/nvmem/rcar-efuse.c index d9a96a1d59c8..b94ff83b7df3 100644 --- a/drivers/nvmem/rcar-efuse.c +++ b/drivers/nvmem/rcar-efuse.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/nvmem/sec-qfprom.c b/drivers/nvmem/sec-qfprom.c index 19799b3fe00a..51d21e65a543 100644 --- a/drivers/nvmem/sec-qfprom.c +++ b/drivers/nvmem/sec-qfprom.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/nvmem/sunplus-ocotp.c b/drivers/nvmem/sunplus-ocotp.c index 30d55b111a64..6884def3ba5f 100644 --- a/drivers/nvmem/sunplus-ocotp.c +++ b/drivers/nvmem/sunplus-ocotp.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/nvmem/u-boot-env.c b/drivers/nvmem/u-boot-env.c index ced414fc9e60..467b288918db 100644 --- a/drivers/nvmem/u-boot-env.c +++ b/drivers/nvmem/u-boot-env.c @@ -3,7 +3,6 @@ * Copyright (C) 2022 Rafał Miłecki */ -#include #include #include #include diff --git a/drivers/nvmem/uniphier-efuse.c b/drivers/nvmem/uniphier-efuse.c index 6ad3295d3195..85f9372fb97c 100644 --- a/drivers/nvmem/uniphier-efuse.c +++ b/drivers/nvmem/uniphier-efuse.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/of/device.c b/drivers/of/device.c index be4e1584e0af..b3dc78f2fa3a 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -8,7 +8,6 @@ #include /* for bus_dma_region */ #include #include -#include #include #include diff --git a/drivers/pci/controller/cadence/pcie-sg2042.c b/drivers/pci/controller/cadence/pcie-sg2042.c index 4a2af4d0713e..265246aa18fd 100644 --- a/drivers/pci/controller/cadence/pcie-sg2042.c +++ b/drivers/pci/controller/cadence/pcie-sg2042.c @@ -6,7 +6,6 @@ * Copyright (C) 2025 Chen Wang */ -#include #include #include #include diff --git a/drivers/pci/controller/dwc/pci-exynos.c b/drivers/pci/controller/dwc/pci-exynos.c index 0bb7d4f5d784..e3c05ade381b 100644 --- a/drivers/pci/controller/dwc/pci-exynos.c +++ b/drivers/pci/controller/dwc/pci-exynos.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include "pcie-designware.h" diff --git a/drivers/pci/controller/dwc/pci-meson.c b/drivers/pci/controller/dwc/pci-meson.c index 225d887cd0a3..7a4da9fae1ea 100644 --- a/drivers/pci/controller/dwc/pci-meson.c +++ b/drivers/pci/controller/dwc/pci-meson.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "pcie-designware.h" diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index 2674cd376f49..348e579e683f 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-keembay.c b/drivers/pci/controller/dwc/pcie-keembay.c index 2459c4d66b88..42fb5f24a223 100644 --- a/drivers/pci/controller/dwc/pcie-keembay.c +++ b/drivers/pci/controller/dwc/pcie-keembay.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c index be20a520255b..04241df8fd59 100644 --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pci/controller/dwc/pcie-stm32.c b/drivers/pci/controller/dwc/pcie-stm32.c index a9e77478443b..349618ea5b9c 100644 --- a/drivers/pci/controller/dwc/pcie-stm32.c +++ b/drivers/pci/controller/dwc/pcie-stm32.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pci/pwrctrl/generic.c b/drivers/pci/pwrctrl/generic.c index 1ae19450a455..a7e599d841e6 100644 --- a/drivers/pci/pwrctrl/generic.c +++ b/drivers/pci/pwrctrl/generic.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c index c7e4beec160a..a308bf4b5fc0 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index 488e1ec34a7f..1555e8a9b3ca 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/perf/arm-ccn.c b/drivers/perf/arm-ccn.c index 8af3563fdf60..c18a0e3205ab 100644 --- a/drivers/perf/arm-ccn.c +++ b/drivers/perf/arm-ccn.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/perf/fujitsu_uncore_pmu.c b/drivers/perf/fujitsu_uncore_pmu.c index c3c6f56474ad..aeeb68c66e1e 100644 --- a/drivers/perf/fujitsu_uncore_pmu.c +++ b/drivers/perf/fujitsu_uncore_pmu.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c index 4df4eebe243e..246cc0333099 100644 --- a/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_mn_pmu.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "hisi_uncore_pmu.h" diff --git a/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c index de3b9cc7aada..616f4af57db7 100644 --- a/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_noc_pmu.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c index 03cb9b564b99..e8186b6e1687 100644 --- a/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c +++ b/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "hisi_uncore_pmu.h" diff --git a/drivers/perf/riscv_pmu_legacy.c b/drivers/perf/riscv_pmu_legacy.c index 93c8e0fdb589..4d6461d6a74f 100644 --- a/drivers/perf/riscv_pmu_legacy.c +++ b/drivers/perf/riscv_pmu_legacy.c @@ -8,7 +8,6 @@ * which are in turn based on sparc64 and x86 code. */ -#include #include #include diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 385af5e6e6d0..dfc886dee5ad 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -10,7 +10,6 @@ #define pr_fmt(fmt) "riscv-pmu-sbi: " fmt -#include #include #include #include diff --git a/drivers/perf/starfive_starlink_pmu.c b/drivers/perf/starfive_starlink_pmu.c index 964897c2baa9..b1c7dc4869bd 100644 --- a/drivers/perf/starfive_starlink_pmu.c +++ b/drivers/perf/starfive_starlink_pmu.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/allwinner/phy-sun50i-usb3.c b/drivers/phy/allwinner/phy-sun50i-usb3.c index 363f9a0df503..84055b720016 100644 --- a/drivers/phy/allwinner/phy-sun50i-usb3.c +++ b/drivers/phy/allwinner/phy-sun50i-usb3.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c index c4a56b9d3289..5e2b7d93bdb1 100644 --- a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c index 14dee73f9cb5..13668764655c 100644 --- a/drivers/phy/amlogic/phy-meson-axg-pcie.c +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c @@ -4,7 +4,6 @@ * * Copyright (C) 2020 Remi Pommarel */ -#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb2.c b/drivers/phy/amlogic/phy-meson-gxl-usb2.c index 6b390304f723..f6bc0ca248f7 100644 --- a/drivers/phy/amlogic/phy-meson-gxl-usb2.c +++ b/drivers/phy/amlogic/phy-meson-gxl-usb2.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c index a553231a9f7c..71e5e281f188 100644 --- a/drivers/phy/amlogic/phy-meson8b-usb2.c +++ b/drivers/phy/amlogic/phy-meson8b-usb2.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/cadence/cdns-dphy-rx.c b/drivers/phy/cadence/cdns-dphy-rx.c index 3ac80141189c..469b8eaca94c 100644 --- a/drivers/phy/cadence/cdns-dphy-rx.c +++ b/drivers/phy/cadence/cdns-dphy-rx.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/hisilicon/phy-hi3670-pcie.c b/drivers/phy/hisilicon/phy-hi3670-pcie.c index dbc7dcce682b..7396c601d874 100644 --- a/drivers/phy/hisilicon/phy-hi3670-pcie.c +++ b/drivers/phy/hisilicon/phy-hi3670-pcie.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/hisilicon/phy-hi6220-usb.c b/drivers/phy/hisilicon/phy-hi6220-usb.c index 22d8d8a8dabe..4e6ff3af381f 100644 --- a/drivers/phy/hisilicon/phy-hi6220-usb.c +++ b/drivers/phy/hisilicon/phy-hi6220-usb.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/phy/intel/phy-intel-keembay-usb.c b/drivers/phy/intel/phy-intel-keembay-usb.c index c8b05f7b2445..7c2192965f68 100644 --- a/drivers/phy/intel/phy-intel-keembay-usb.c +++ b/drivers/phy/intel/phy-intel-keembay-usb.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/marvell/phy-mmp3-hsic.c b/drivers/phy/marvell/phy-mmp3-hsic.c index 72ab6da0ebc3..41bfa542b73e 100644 --- a/drivers/phy/marvell/phy-mmp3-hsic.c +++ b/drivers/phy/marvell/phy-mmp3-hsic.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/phy/marvell/phy-mmp3-usb.c b/drivers/phy/marvell/phy-mmp3-usb.c index 5b71deb08851..04c0bada3519 100644 --- a/drivers/phy/marvell/phy-mmp3-usb.c +++ b/drivers/phy/marvell/phy-mmp3-usb.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/phy/marvell/phy-mvebu-sata.c b/drivers/phy/marvell/phy-mvebu-sata.c index 89a5a2b69d80..51a4646e2933 100644 --- a/drivers/phy/marvell/phy-mvebu-sata.c +++ b/drivers/phy/marvell/phy-mvebu-sata.c @@ -10,7 +10,6 @@ #include #include #include -#include #include struct priv { diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c index 0cb5a25b1b7a..fc19e0fa8ed5 100644 --- a/drivers/phy/mediatek/phy-mtk-ufs.c +++ b/drivers/phy/mediatek/phy-mtk-ufs.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/phy-eyeq5-eth.c b/drivers/phy/phy-eyeq5-eth.c index c03d77c360f7..d1107bc605c1 100644 --- a/drivers/phy/phy-eyeq5-eth.c +++ b/drivers/phy/phy-eyeq5-eth.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/phy-snps-eusb2.c b/drivers/phy/phy-snps-eusb2.c index f90bf7e95463..af4fa17ac6cb 100644 --- a/drivers/phy/phy-snps-eusb2.c +++ b/drivers/phy/phy-snps-eusb2.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/qualcomm/phy-ath79-usb.c b/drivers/phy/qualcomm/phy-ath79-usb.c index f8d0199c6e78..09a77e556ece 100644 --- a/drivers/phy/qualcomm/phy-ath79-usb.c +++ b/drivers/phy/qualcomm/phy-ath79-usb.c @@ -5,7 +5,6 @@ * Copyright (C) 2015-2018 Alban Bedel */ -#include #include #include #include diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c index 0f69060aa5d5..cbd780556da8 100644 --- a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c +++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index fba35510d88c..f68de14366db 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c index f9d8fb1ab1ec..6c218ce3396d 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c index 50979787db5c..b0cba0f3e17e 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c index 8cf61aab81b1..85d6640ff4c4 100644 --- a/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c +++ b/drivers/pinctrl/aspeed/pinctrl-aspeed-g6.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/bcm/pinctrl-bcm4908.c b/drivers/pinctrl/bcm/pinctrl-bcm4908.c index 57969cdbc635..709ef4add927 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm4908.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm4908.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c index 59d2ce8462d8..a4aa4146b530 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm63xx.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm63xx.c @@ -8,7 +8,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx-scmi.c b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c index e14bdbc7bea7..613552e35070 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx-scmi.c +++ b/drivers/pinctrl/freescale/pinctrl-imx-scmi.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx23.c b/drivers/pinctrl/freescale/pinctrl-imx23.c index 0404efbf2a86..7655c1a0cd66 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx23.c +++ b/drivers/pinctrl/freescale/pinctrl-imx23.c @@ -6,7 +6,6 @@ // Copyright 2012 Freescale Semiconductor, Inc. #include -#include #include #include #include "pinctrl-mxs.h" diff --git a/drivers/pinctrl/freescale/pinctrl-imx25.c b/drivers/pinctrl/freescale/pinctrl-imx25.c index d2b0b6aad306..e1604c3bdcec 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx25.c +++ b/drivers/pinctrl/freescale/pinctrl-imx25.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx27.c b/drivers/pinctrl/freescale/pinctrl-imx27.c index afeb39957203..37fdac794455 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx27.c +++ b/drivers/pinctrl/freescale/pinctrl-imx27.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx28.c b/drivers/pinctrl/freescale/pinctrl-imx28.c index eb847151713a..aa013ba280b3 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx28.c +++ b/drivers/pinctrl/freescale/pinctrl-imx28.c @@ -6,7 +6,6 @@ // Copyright 2012 Freescale Semiconductor, Inc. #include -#include #include #include #include "pinctrl-mxs.h" diff --git a/drivers/pinctrl/freescale/pinctrl-imx35.c b/drivers/pinctrl/freescale/pinctrl-imx35.c index 1546517d8110..88aa0583b0d2 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx35.c +++ b/drivers/pinctrl/freescale/pinctrl-imx35.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx50.c b/drivers/pinctrl/freescale/pinctrl-imx50.c index 9b044aee4f7c..b54f98cfa63c 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx50.c +++ b/drivers/pinctrl/freescale/pinctrl-imx50.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx51.c b/drivers/pinctrl/freescale/pinctrl-imx51.c index e580c022bebe..fb0a81a6d29c 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx51.c +++ b/drivers/pinctrl/freescale/pinctrl-imx51.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx53.c b/drivers/pinctrl/freescale/pinctrl-imx53.c index 1034192ab410..3c94ec4dffbe 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx53.c +++ b/drivers/pinctrl/freescale/pinctrl-imx53.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx6dl.c b/drivers/pinctrl/freescale/pinctrl-imx6dl.c index 09542fdcd405..6a1cafa69230 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6dl.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6dl.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx6q.c b/drivers/pinctrl/freescale/pinctrl-imx6q.c index ae5cec74a3e8..3ba2ff757322 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6q.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6q.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sl.c b/drivers/pinctrl/freescale/pinctrl-imx6sl.c index 3111f50263f6..15483f10f743 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6sl.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6sl.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sll.c b/drivers/pinctrl/freescale/pinctrl-imx6sll.c index 72a7214811ab..27d24f5d58e4 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6sll.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6sll.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx6sx.c b/drivers/pinctrl/freescale/pinctrl-imx6sx.c index aa76bc6d7402..4e4b78b5b42d 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6sx.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6sx.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c index ba0ef1ea5722..063805daee03 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx7ulp.c +++ b/drivers/pinctrl/freescale/pinctrl-imx7ulp.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx8dxl.c b/drivers/pinctrl/freescale/pinctrl-imx8dxl.c index 7dec709ebd9a..fe957d09eb40 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx8dxl.c +++ b/drivers/pinctrl/freescale/pinctrl-imx8dxl.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx8mq.c b/drivers/pinctrl/freescale/pinctrl-imx8mq.c index e59e4fc80193..845aed2f0e34 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx8mq.c +++ b/drivers/pinctrl/freescale/pinctrl-imx8mq.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx8qxp.c b/drivers/pinctrl/freescale/pinctrl-imx8qxp.c index 37ef3229231b..884c8311be70 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx8qxp.c +++ b/drivers/pinctrl/freescale/pinctrl-imx8qxp.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx8ulp.c b/drivers/pinctrl/freescale/pinctrl-imx8ulp.c index 5632c7285147..88af25b0d48e 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx8ulp.c +++ b/drivers/pinctrl/freescale/pinctrl-imx8ulp.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx91.c b/drivers/pinctrl/freescale/pinctrl-imx91.c index 5421141c586a..312a81d79fb3 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx91.c +++ b/drivers/pinctrl/freescale/pinctrl-imx91.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-imx93.c b/drivers/pinctrl/freescale/pinctrl-imx93.c index 5977dda3b759..8458a41c583e 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx93.c +++ b/drivers/pinctrl/freescale/pinctrl-imx93.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c index 76adcc5abdec..76a4bc0181a0 100644 --- a/drivers/pinctrl/freescale/pinctrl-vf610.c +++ b/drivers/pinctrl/freescale/pinctrl-vf610.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-alderlake.c b/drivers/pinctrl/intel/pinctrl-alderlake.c index dcb541976f2f..415bc0a16957 100644 --- a/drivers/pinctrl/intel/pinctrl-alderlake.c +++ b/drivers/pinctrl/intel/pinctrl-alderlake.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c index a33100f28488..269b8e25db84 100644 --- a/drivers/pinctrl/intel/pinctrl-broxton.c +++ b/drivers/pinctrl/intel/pinctrl-broxton.c @@ -6,7 +6,6 @@ * Author: Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-cannonlake.c b/drivers/pinctrl/intel/pinctrl-cannonlake.c index baa7c9a62ff9..b45480e05312 100644 --- a/drivers/pinctrl/intel/pinctrl-cannonlake.c +++ b/drivers/pinctrl/intel/pinctrl-cannonlake.c @@ -7,7 +7,6 @@ * Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-cedarfork.c b/drivers/pinctrl/intel/pinctrl-cedarfork.c index 578e1ee57acf..02fd1cc4fd1b 100644 --- a/drivers/pinctrl/intel/pinctrl-cedarfork.c +++ b/drivers/pinctrl/intel/pinctrl-cedarfork.c @@ -6,7 +6,6 @@ * Author: Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-denverton.c b/drivers/pinctrl/intel/pinctrl-denverton.c index 09aee90dee82..47636a9719ed 100644 --- a/drivers/pinctrl/intel/pinctrl-denverton.c +++ b/drivers/pinctrl/intel/pinctrl-denverton.c @@ -6,7 +6,6 @@ * Author: Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-elkhartlake.c b/drivers/pinctrl/intel/pinctrl-elkhartlake.c index 8a24ef12141d..822724c7571b 100644 --- a/drivers/pinctrl/intel/pinctrl-elkhartlake.c +++ b/drivers/pinctrl/intel/pinctrl-elkhartlake.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-emmitsburg.c b/drivers/pinctrl/intel/pinctrl-emmitsburg.c index 3b63b6dd2560..f5a602ba49af 100644 --- a/drivers/pinctrl/intel/pinctrl-emmitsburg.c +++ b/drivers/pinctrl/intel/pinctrl-emmitsburg.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-geminilake.c b/drivers/pinctrl/intel/pinctrl-geminilake.c index 8dcac4fe8493..21d0d5051b04 100644 --- a/drivers/pinctrl/intel/pinctrl-geminilake.c +++ b/drivers/pinctrl/intel/pinctrl-geminilake.c @@ -6,7 +6,6 @@ * Author: Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-intel-platform.c b/drivers/pinctrl/intel/pinctrl-intel-platform.c index 61dd579e3f97..c83e3859b655 100644 --- a/drivers/pinctrl/intel/pinctrl-intel-platform.c +++ b/drivers/pinctrl/intel/pinctrl-intel-platform.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-jasperlake.c b/drivers/pinctrl/intel/pinctrl-jasperlake.c index a8f65c3dbb1c..55780654a847 100644 --- a/drivers/pinctrl/intel/pinctrl-jasperlake.c +++ b/drivers/pinctrl/intel/pinctrl-jasperlake.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-lakefield.c b/drivers/pinctrl/intel/pinctrl-lakefield.c index 39872c352ac2..8a1ef3b75ea0 100644 --- a/drivers/pinctrl/intel/pinctrl-lakefield.c +++ b/drivers/pinctrl/intel/pinctrl-lakefield.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-lewisburg.c b/drivers/pinctrl/intel/pinctrl-lewisburg.c index ebbc94047b6f..4bf5010afd71 100644 --- a/drivers/pinctrl/intel/pinctrl-lewisburg.c +++ b/drivers/pinctrl/intel/pinctrl-lewisburg.c @@ -6,7 +6,6 @@ * Author: Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c index 83b4d1862545..5cf54bc18f86 100644 --- a/drivers/pinctrl/intel/pinctrl-merrifield.c +++ b/drivers/pinctrl/intel/pinctrl-merrifield.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-meteorlake.c b/drivers/pinctrl/intel/pinctrl-meteorlake.c index 3f5070a339bf..6fefee7827ed 100644 --- a/drivers/pinctrl/intel/pinctrl-meteorlake.c +++ b/drivers/pinctrl/intel/pinctrl-meteorlake.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-meteorpoint.c b/drivers/pinctrl/intel/pinctrl-meteorpoint.c index bff7be1f137d..f7fe3c20951c 100644 --- a/drivers/pinctrl/intel/pinctrl-meteorpoint.c +++ b/drivers/pinctrl/intel/pinctrl-meteorpoint.c @@ -6,7 +6,6 @@ * Author: Andy Shevchenko */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-moorefield.c b/drivers/pinctrl/intel/pinctrl-moorefield.c index 30f9a4481827..59f46b0e2156 100644 --- a/drivers/pinctrl/intel/pinctrl-moorefield.c +++ b/drivers/pinctrl/intel/pinctrl-moorefield.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c index 308651091d9c..77ac32ab9577 100644 --- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c +++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c @@ -7,7 +7,6 @@ * Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/intel/pinctrl-tigerlake.c b/drivers/pinctrl/intel/pinctrl-tigerlake.c index ae231f7fba49..3ac35a153e8c 100644 --- a/drivers/pinctrl/intel/pinctrl-tigerlake.c +++ b/drivers/pinctrl/intel/pinctrl-tigerlake.c @@ -7,7 +7,6 @@ * Mika Westerberg */ -#include #include #include #include diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index 4507dc8b5563..18295b15ecd9 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -619,7 +619,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc) pc->chip.set = meson_gpio_set; pc->chip.base = -1; pc->chip.ngpio = pc->data->num_pins; - pc->chip.can_sleep = true; + pc->chip.can_sleep = false; ret = gpiochip_add_data(&pc->chip, pc); if (ret) { diff --git a/drivers/pinctrl/microchip/pinctrl-mpfs-iomux0.c b/drivers/pinctrl/microchip/pinctrl-mpfs-iomux0.c index 1b060a038920..a390caa83181 100644 --- a/drivers/pinctrl/microchip/pinctrl-mpfs-iomux0.c +++ b/drivers/pinctrl/microchip/pinctrl-mpfs-iomux0.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c b/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c index 15d73ea1028c..ea1026a0d22c 100644 --- a/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c +++ b/drivers/pinctrl/microchip/pinctrl-mpfs-mssio.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/microchip/pinctrl-pic64gx-gpio2.c b/drivers/pinctrl/microchip/pinctrl-pic64gx-gpio2.c index a0b3e839cf3b..633ef40e1c27 100644 --- a/drivers/pinctrl/microchip/pinctrl-pic64gx-gpio2.c +++ b/drivers/pinctrl/microchip/pinctrl-pic64gx-gpio2.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c index 9d4627c80a52..132615959e67 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c +++ b/drivers/pinctrl/nuvoton/pinctrl-ma35d1.c @@ -7,7 +7,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c index 13ed87d5d30c..0df749cbcba8 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm7xx.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c index 0aae1a253459..a68d55caef25 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c +++ b/drivers/pinctrl/nuvoton/pinctrl-npcm8xx.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c index d624a4d302a8..bc030abdadca 100644 --- a/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c +++ b/drivers/pinctrl/nuvoton/pinctrl-wpcm450.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c index e713dea98aa8..3d2f477aac9e 100644 --- a/drivers/pinctrl/pinctrl-as3722.c +++ b/drivers/pinctrl/pinctrl-as3722.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c index 093ae7c1dae5..9a54b259ef4b 100644 --- a/drivers/pinctrl/pinctrl-cy8c95x0.c +++ b/drivers/pinctrl/pinctrl-cy8c95x0.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-da850-pupd.c b/drivers/pinctrl/pinctrl-da850-pupd.c index 5eb248663e17..c5f243d1311f 100644 --- a/drivers/pinctrl/pinctrl-da850-pupd.c +++ b/drivers/pinctrl/pinctrl-da850-pupd.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c index 2e16f09aeb47..58f22b4a5a6f 100644 --- a/drivers/pinctrl/pinctrl-digicolor.c +++ b/drivers/pinctrl/pinctrl-digicolor.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/pinctrl-eic7700.c b/drivers/pinctrl/pinctrl-eic7700.c index ffcd0ec5c2dc..d553ec20c619 100644 --- a/drivers/pinctrl/pinctrl-eic7700.c +++ b/drivers/pinctrl/pinctrl-eic7700.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-eyeq5.c b/drivers/pinctrl/pinctrl-eyeq5.c index dcdf80f07a90..19d845b47939 100644 --- a/drivers/pinctrl/pinctrl-eyeq5.c +++ b/drivers/pinctrl/pinctrl-eyeq5.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-ingenic.c b/drivers/pinctrl/pinctrl-ingenic.c index 29d7f4e54bc7..1aa6a6dc1209 100644 --- a/drivers/pinctrl/pinctrl-ingenic.c +++ b/drivers/pinctrl/pinctrl-ingenic.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-loongson2.c b/drivers/pinctrl/pinctrl-loongson2.c index 4d4fbeadafb7..7d04fa81d2e5 100644 --- a/drivers/pinctrl/pinctrl-loongson2.c +++ b/drivers/pinctrl/pinctrl-loongson2.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c index 5e0201768323..9431810ffaff 100644 --- a/drivers/pinctrl/pinctrl-lpc18xx.c +++ b/drivers/pinctrl/pinctrl-lpc18xx.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/pinctrl-max77620.c b/drivers/pinctrl/pinctrl-max77620.c index c47eccce7dc0..0fa28d697e8c 100644 --- a/drivers/pinctrl/pinctrl-max77620.c +++ b/drivers/pinctrl/pinctrl-max77620.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c index b89b3169e8be..a4f0ba728c6e 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08.c +++ b/drivers/pinctrl/pinctrl-mcp23s08.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-mcp23s08_i2c.c b/drivers/pinctrl/pinctrl-mcp23s08_i2c.c index f3dffa3c74d3..928b66531858 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08_i2c.c +++ b/drivers/pinctrl/pinctrl-mcp23s08_i2c.c @@ -2,7 +2,6 @@ /* MCP23S08 I2C GPIO driver */ #include -#include #include #include diff --git a/drivers/pinctrl/pinctrl-mcp23s08_spi.c b/drivers/pinctrl/pinctrl-mcp23s08_spi.c index 30775d31bd69..bacebcff67ef 100644 --- a/drivers/pinctrl/pinctrl-mcp23s08_spi.c +++ b/drivers/pinctrl/pinctrl-mcp23s08_spi.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* MCP23S08 SPI GPIO driver */ -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-microchip-sgpio.c b/drivers/pinctrl/pinctrl-microchip-sgpio.c index 7a6cb5f502b0..aa0f7c809978 100644 --- a/drivers/pinctrl/pinctrl-microchip-sgpio.c +++ b/drivers/pinctrl/pinctrl-microchip-sgpio.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-mlxbf3.c b/drivers/pinctrl/pinctrl-mlxbf3.c index fcd9d46de89f..1b285c9ee05a 100644 --- a/drivers/pinctrl/pinctrl-mlxbf3.c +++ b/drivers/pinctrl/pinctrl-mlxbf3.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c index 0b33b01dbaad..cc5cd2a538c5 100644 --- a/drivers/pinctrl/pinctrl-pistachio.c +++ b/drivers/pinctrl/pinctrl-pistachio.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-scmi.c b/drivers/pinctrl/pinctrl-scmi.c index f22be6b7b82a..1bb36ca477b7 100644 --- a/drivers/pinctrl/pinctrl-scmi.c +++ b/drivers/pinctrl/pinctrl-scmi.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-th1520.c b/drivers/pinctrl/pinctrl-th1520.c index 4d5a99483dee..50a5889df7c4 100644 --- a/drivers/pinctrl/pinctrl-th1520.c +++ b/drivers/pinctrl/pinctrl-th1520.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/pinctrl-tps6594.c b/drivers/pinctrl/pinctrl-tps6594.c index 55dfa843e35e..456a3cfc8de9 100644 --- a/drivers/pinctrl/pinctrl-tps6594.c +++ b/drivers/pinctrl/pinctrl-tps6594.c @@ -10,7 +10,6 @@ #include #include #include -#include #include diff --git a/drivers/pinctrl/qcom/pinctrl-ipq5018.c b/drivers/pinctrl/qcom/pinctrl-ipq5018.c index 0698c8f0110b..03cfba9534f8 100644 --- a/drivers/pinctrl/qcom/pinctrl-ipq5018.c +++ b/drivers/pinctrl/qcom/pinctrl-ipq5018.c @@ -4,7 +4,6 @@ */ #include -#include #include #include "pinctrl-msm.h" diff --git a/drivers/pinctrl/spear/pinctrl-spear1310.c b/drivers/pinctrl/spear/pinctrl-spear1310.c index fb624a051e26..4885648050bf 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1310.c +++ b/drivers/pinctrl/spear/pinctrl-spear1310.c @@ -11,7 +11,6 @@ #include #include -#include #include #include "pinctrl-spear.h" diff --git a/drivers/pinctrl/spear/pinctrl-spear1340.c b/drivers/pinctrl/spear/pinctrl-spear1340.c index 48f068cf5e24..f6b681cfe9e8 100644 --- a/drivers/pinctrl/spear/pinctrl-spear1340.c +++ b/drivers/pinctrl/spear/pinctrl-spear1340.c @@ -11,7 +11,6 @@ #include #include -#include #include #include "pinctrl-spear.h" diff --git a/drivers/pinctrl/spear/pinctrl-spear300.c b/drivers/pinctrl/spear/pinctrl-spear300.c index 7530252ef7bc..4391185d1e46 100644 --- a/drivers/pinctrl/spear/pinctrl-spear300.c +++ b/drivers/pinctrl/spear/pinctrl-spear300.c @@ -11,7 +11,6 @@ #include #include -#include #include #include "pinctrl-spear3xx.h" diff --git a/drivers/pinctrl/spear/pinctrl-spear310.c b/drivers/pinctrl/spear/pinctrl-spear310.c index c476e5478646..6418bb666bfb 100644 --- a/drivers/pinctrl/spear/pinctrl-spear310.c +++ b/drivers/pinctrl/spear/pinctrl-spear310.c @@ -11,7 +11,6 @@ #include #include -#include #include #include "pinctrl-spear3xx.h" diff --git a/drivers/pinctrl/spear/pinctrl-spear320.c b/drivers/pinctrl/spear/pinctrl-spear320.c index 401477cfbf57..73a208977600 100644 --- a/drivers/pinctrl/spear/pinctrl-spear320.c +++ b/drivers/pinctrl/spear/pinctrl-spear320.c @@ -11,7 +11,6 @@ #include #include -#include #include #include "pinctrl-spear3xx.h" diff --git a/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c b/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c index d14f382f2392..e6ca2701dbd1 100644 --- a/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c +++ b/drivers/pinctrl/sprd/pinctrl-sprd-sc9860.c @@ -5,7 +5,6 @@ */ #include -#include #include #include "pinctrl-sprd.h" diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c index 25cb98d9c54e..37da176cad49 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7100.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c index 3433b3c91692..fab18e895330 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-aon.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c index 44f84e4c29bf..77039012521a 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110-sys.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c index ec359cb873c4..7fcb6cdc1e86 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jh7110.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pinctrl/tegra/pinctrl-tegra234.c b/drivers/pinctrl/tegra/pinctrl-tegra234.c index 86c2b84e792d..fb9feae590f8 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra234.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra234.c @@ -5,7 +5,6 @@ * Copyright (c) 2021-2023, NVIDIA CORPORATION. All rights reserved. */ -#include #include #include #include diff --git a/drivers/pinctrl/tegra/pinctrl-tegra238.c b/drivers/pinctrl/tegra/pinctrl-tegra238.c index d3809594a5b5..ec482365f14f 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra238.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra238.c @@ -5,7 +5,6 @@ * Copyright (c) 2022-2026, NVIDIA CORPORATION. All rights reserved. */ -#include #include #include #include diff --git a/drivers/pinctrl/tegra/pinctrl-tegra264.c b/drivers/pinctrl/tegra/pinctrl-tegra264.c index 5a0c91aaba3a..be64fba34dce 100644 --- a/drivers/pinctrl/tegra/pinctrl-tegra264.c +++ b/drivers/pinctrl/tegra/pinctrl-tegra264.c @@ -5,7 +5,6 @@ * Copyright (c) 2024-2026, NVIDIA CORPORATION. All rights reserved. */ -#include #include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c index 65ed20bc1fa2..f1019f041f11 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld11.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c index a68b21fbd0c7..bb52497d5fc4 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c index 88fd68f86a85..3aebc77529ed 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld4.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c index 374c029ebc02..07706b57bc37 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld6b.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-nx1.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-nx1.c index 4fd3ec511d37..25a5e4db6e98 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-nx1.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-nx1.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c index 4f63d7b1a252..bc20a2d0d64d 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c index 4277d494a348..39915be4128c 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c index 2a9dbf969f0b..cd6429f58276 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs2.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs3.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs3.c index ab3bd2d9c6c7..d07788c785d4 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs3.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pxs3.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c index 087e8db8f11d..78d254070988 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-sld8.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c index 47e03014dcbe..399ab85b6191 100644 --- a/drivers/platform/chrome/cros_ec_chardev.c +++ b/drivers/platform/chrome/cros_ec_chardev.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c index d10f9561990c..139cab6fcba1 100644 --- a/drivers/platform/chrome/cros_ec_debugfs.c +++ b/drivers/platform/chrome/cros_ec_debugfs.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index f69f2f6de276..ac919c14c631 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_ec_sensorhub.c b/drivers/platform/chrome/cros_ec_sensorhub.c index f938c3fc84e4..f7019fb80a76 100644 --- a/drivers/platform/chrome/cros_ec_sensorhub.c +++ b/drivers/platform/chrome/cros_ec_sensorhub.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index 9d3767ab1548..b668a3cc118e 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c index 5ee8adaa6564..061e84b32b04 100644 --- a/drivers/platform/chrome/cros_ec_vbc.c +++ b/drivers/platform/chrome/cros_ec_vbc.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_kbd_led_backlight.c b/drivers/platform/chrome/cros_kbd_led_backlight.c index 80dc52833dc9..906eb490e506 100644 --- a/drivers/platform/chrome/cros_kbd_led_backlight.c +++ b/drivers/platform/chrome/cros_kbd_led_backlight.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_usbpd_logger.c b/drivers/platform/chrome/cros_usbpd_logger.c index d343e1ab6f08..060a49f2b962 100644 --- a/drivers/platform/chrome/cros_usbpd_logger.c +++ b/drivers/platform/chrome/cros_usbpd_logger.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index c90174360004..828f00a3191b 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/wilco_ec/core.c b/drivers/platform/chrome/wilco_ec/core.c index 9f978e531e1f..fd2a9bc8327c 100644 --- a/drivers/platform/chrome/wilco_ec/core.c +++ b/drivers/platform/chrome/wilco_ec/core.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/wilco_ec/debugfs.c b/drivers/platform/chrome/wilco_ec/debugfs.c index 0617292b5cd7..e43ad67b9bcb 100644 --- a/drivers/platform/chrome/wilco_ec/debugfs.c +++ b/drivers/platform/chrome/wilco_ec/debugfs.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/chrome/wilco_ec/telemetry.c b/drivers/platform/chrome/wilco_ec/telemetry.c index cadb68fa0a40..05e35d1b16a6 100644 --- a/drivers/platform/chrome/wilco_ec/telemetry.c +++ b/drivers/platform/chrome/wilco_ec/telemetry.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c index 75c86f5688c9..fa241ca8feb0 100644 --- a/drivers/platform/goldfish/goldfish_pipe.c +++ b/drivers/platform/goldfish/goldfish_pipe.c @@ -48,7 +48,6 @@ */ #include -#include #include #include #include diff --git a/drivers/platform/x86/asus-tf103c-dock.c b/drivers/platform/x86/asus-tf103c-dock.c index f09a3fc6524a..92466477de9a 100644 --- a/drivers/platform/x86/asus-tf103c-dock.c +++ b/drivers/platform/x86/asus-tf103c-dock.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/intel/atomisp2/led.c b/drivers/platform/x86/intel/atomisp2/led.c index 10077a61d8c5..344ea57d9736 100644 --- a/drivers/platform/x86/intel/atomisp2/led.c +++ b/drivers/platform/x86/intel/atomisp2/led.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/platform/x86/intel/atomisp2/pm.c b/drivers/platform/x86/intel/atomisp2/pm.c index 805fc0d8515c..ad1f99140962 100644 --- a/drivers/platform/x86/intel/atomisp2/pm.c +++ b/drivers/platform/x86/intel/atomisp2/pm.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/drivers/platform/x86/intel/bxtwc_tmu.c b/drivers/platform/x86/intel/bxtwc_tmu.c index 99437b2ccc25..b3666704d85b 100644 --- a/drivers/platform/x86/intel/bxtwc_tmu.c +++ b/drivers/platform/x86/intel/bxtwc_tmu.c @@ -10,7 +10,6 @@ */ #include -#include #include #include #include diff --git a/drivers/platform/x86/intel/ehl_pse_io.c b/drivers/platform/x86/intel/ehl_pse_io.c index 861e14808b35..f75f3a8cc6b0 100644 --- a/drivers/platform/x86/intel/ehl_pse_io.c +++ b/drivers/platform/x86/intel/ehl_pse_io.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/intel/plr_tpmi.c b/drivers/platform/x86/intel/plr_tpmi.c index 8faecc311038..f98c241edee4 100644 --- a/drivers/platform/x86/intel/plr_tpmi.c +++ b/drivers/platform/x86/intel/plr_tpmi.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/intel/pmc/pwrm_telemetry.c b/drivers/platform/x86/intel/pmc/pwrm_telemetry.c index 62b0e9fc7920..4cde241e01d6 100644 --- a/drivers/platform/x86/intel/pmc/pwrm_telemetry.c +++ b/drivers/platform/x86/intel/pmc/pwrm_telemetry.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/intel/punit_ipc.c b/drivers/platform/x86/intel/punit_ipc.c index 14513010daad..6d770b950dfb 100644 --- a/drivers/platform/x86/intel/punit_ipc.c +++ b/drivers/platform/x86/intel/punit_ipc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/platform/x86/intel_scu_pltdrv.c b/drivers/platform/x86/intel_scu_pltdrv.c index 0892362acd7b..d5ab62cbf5cc 100644 --- a/drivers/platform/x86/intel_scu_pltdrv.c +++ b/drivers/platform/x86/intel_scu_pltdrv.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c index 0157e233e430..dfe4532ebe56 100644 --- a/drivers/platform/x86/msi-ec.c +++ b/drivers/platform/x86/msi-ec.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/platform/x86/nvidia-wmi-ec-backlight.c b/drivers/platform/x86/nvidia-wmi-ec-backlight.c index 1b572c90c76e..b4eebfb96fe5 100644 --- a/drivers/platform/x86/nvidia-wmi-ec-backlight.c +++ b/drivers/platform/x86/nvidia-wmi-ec-backlight.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/platform/x86/quickstart.c b/drivers/platform/x86/quickstart.c index acb58518be37..186a243a012d 100644 --- a/drivers/platform/x86/quickstart.c +++ b/drivers/platform/x86/quickstart.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.c b/drivers/platform/x86/uniwill/uniwill-wmi.c index e97aa988a90c..afcbfa4f7552 100644 --- a/drivers/platform/x86/uniwill/uniwill-wmi.c +++ b/drivers/platform/x86/uniwill/uniwill-wmi.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/x86-android-tablets/dmi.c b/drivers/platform/x86/x86-android-tablets/dmi.c index 4a5720d6fc1d..2ab53030e5a4 100644 --- a/drivers/platform/x86/x86-android-tablets/dmi.c +++ b/drivers/platform/x86/x86-android-tablets/dmi.c @@ -10,7 +10,6 @@ #include #include -#include #include #include "x86-android-tablets.h" diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index 2498390958ad..c756961ae5fd 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -13,6 +13,7 @@ #include #include #include +#include #include struct gpio_desc; diff --git a/drivers/pmdomain/actions/owl-sps.c b/drivers/pmdomain/actions/owl-sps.c index 3a586d1f3256..bf5eb80cc3b4 100644 --- a/drivers/pmdomain/actions/owl-sps.c +++ b/drivers/pmdomain/actions/owl-sps.c @@ -8,7 +8,6 @@ * Copyright (c) 2017 Andreas Färber */ -#include #include #include #include diff --git a/drivers/pmdomain/imx/imx93-pd.c b/drivers/pmdomain/imx/imx93-pd.c index d68273330687..50d1eb852f75 100644 --- a/drivers/pmdomain/imx/imx93-pd.c +++ b/drivers/pmdomain/imx/imx93-pd.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pmdomain/marvell/pxa1908-power-controller.c b/drivers/pmdomain/marvell/pxa1908-power-controller.c index 543e8d33ac0c..4a957ab0e4f5 100644 --- a/drivers/pmdomain/marvell/pxa1908-power-controller.c +++ b/drivers/pmdomain/marvell/pxa1908-power-controller.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index a0927081a003..fbf03ff007eb 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -10,7 +10,6 @@ #include #include #include -#include #include "../base.h" #include "pnpacpi.h" diff --git a/drivers/power/reset/brcm-kona-reset.c b/drivers/power/reset/brcm-kona-reset.c index ee3f1bb97653..60d7000412f1 100644 --- a/drivers/power/reset/brcm-kona-reset.c +++ b/drivers/power/reset/brcm-kona-reset.c @@ -2,7 +2,6 @@ // Copyright (C) 2016 Broadcom #include -#include #include #include diff --git a/drivers/power/reset/ep93xx-restart.c b/drivers/power/reset/ep93xx-restart.c index 57cfb8620faf..119394bb0305 100644 --- a/drivers/power/reset/ep93xx-restart.c +++ b/drivers/power/reset/ep93xx-restart.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/reset/gpio-poweroff.c b/drivers/power/reset/gpio-poweroff.c index 3eaae352ffb9..1cd5900be038 100644 --- a/drivers/power/reset/gpio-poweroff.c +++ b/drivers/power/reset/gpio-poweroff.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c index 90c664d344d0..c3a0435938c8 100644 --- a/drivers/power/reset/ltc2952-poweroff.c +++ b/drivers/power/reset/ltc2952-poweroff.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/reset/macsmc-reboot.c b/drivers/power/reset/macsmc-reboot.c index e9702acdd366..9fc36fa68676 100644 --- a/drivers/power/reset/macsmc-reboot.c +++ b/drivers/power/reset/macsmc-reboot.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/reset/ocelot-reset.c b/drivers/power/reset/ocelot-reset.c index 56be64decf54..9d4b8afb6cbb 100644 --- a/drivers/power/reset/ocelot-reset.c +++ b/drivers/power/reset/ocelot-reset.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/reset/pwr-mlxbf.c b/drivers/power/reset/pwr-mlxbf.c index 4f1cd1c0018c..15d92c9f64dd 100644 --- a/drivers/power/reset/pwr-mlxbf.c +++ b/drivers/power/reset/pwr-mlxbf.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/reset/qemu-virt-ctrl.c b/drivers/power/reset/qemu-virt-ctrl.c index aa8355270b2c..97875007fda3 100644 --- a/drivers/power/reset/qemu-virt-ctrl.c +++ b/drivers/power/reset/qemu-virt-ctrl.c @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/drivers/power/reset/sc27xx-poweroff.c b/drivers/power/reset/sc27xx-poweroff.c index 6376706bf561..a9378247e3fb 100644 --- a/drivers/power/reset/sc27xx-poweroff.c +++ b/drivers/power/reset/sc27xx-poweroff.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/drivers/power/reset/spacemit-p1-reboot.c b/drivers/power/reset/spacemit-p1-reboot.c index 84026b042ea2..c0454b547718 100644 --- a/drivers/power/reset/spacemit-p1-reboot.c +++ b/drivers/power/reset/spacemit-p1-reboot.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/power/reset/tdx-ec-poweroff.c b/drivers/power/reset/tdx-ec-poweroff.c index 8040aa03d74d..b4f1c87f5651 100644 --- a/drivers/power/reset/tdx-ec-poweroff.c +++ b/drivers/power/reset/tdx-ec-poweroff.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/reset/tps65086-restart.c b/drivers/power/reset/tps65086-restart.c index 37d248a9df17..44a290f961ff 100644 --- a/drivers/power/reset/tps65086-restart.c +++ b/drivers/power/reset/tps65086-restart.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/drivers/power/sequencing/pwrseq-pcie-m2.c b/drivers/power/sequencing/pwrseq-pcie-m2.c index b5ed80d03953..ddfe6ca82494 100644 --- a/drivers/power/sequencing/pwrseq-pcie-m2.c +++ b/drivers/power/sequencing/pwrseq-pcie-m2.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/sequencing/pwrseq-qcom-wcn.c b/drivers/power/sequencing/pwrseq-qcom-wcn.c index b55b4317e21b..d41793e1fcd9 100644 --- a/drivers/power/sequencing/pwrseq-qcom-wcn.c +++ b/drivers/power/sequencing/pwrseq-qcom-wcn.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/adp5061.c b/drivers/power/supply/adp5061.c index 7d5754c24553..7478986e6b3c 100644 --- a/drivers/power/supply/adp5061.c +++ b/drivers/power/supply/adp5061.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/bd71828-power.c b/drivers/power/supply/bd71828-power.c index b671563ead79..19f24f859666 100644 --- a/drivers/power/supply/bd71828-power.c +++ b/drivers/power/supply/bd71828-power.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/bd99954-charger.c b/drivers/power/supply/bd99954-charger.c index 5c447b088223..b3068c2197c7 100644 --- a/drivers/power/supply/bd99954-charger.c +++ b/drivers/power/supply/bd99954-charger.c @@ -61,7 +61,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 6700d578a98f..8e28f86ae09f 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -5,7 +5,6 @@ * Author: Mark A. Greer */ -#include #include #include #include diff --git a/drivers/power/supply/chagall-battery.c b/drivers/power/supply/chagall-battery.c index 8b05422aca6f..129566d0bd9d 100644 --- a/drivers/power/supply/chagall-battery.c +++ b/drivers/power/supply/chagall-battery.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/cpcap-charger.c b/drivers/power/supply/cpcap-charger.c index 24221244b45b..ec8d2a9245d9 100644 --- a/drivers/power/supply/cpcap-charger.c +++ b/drivers/power/supply/cpcap-charger.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/cros_charge-control.c b/drivers/power/supply/cros_charge-control.c index e1b8f3b1b7de..e0f168624807 100644 --- a/drivers/power/supply/cros_charge-control.c +++ b/drivers/power/supply/cros_charge-control.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/cros_peripheral_charger.c b/drivers/power/supply/cros_peripheral_charger.c index 9f67a6dbd94e..612bc7badac0 100644 --- a/drivers/power/supply/cros_peripheral_charger.c +++ b/drivers/power/supply/cros_peripheral_charger.c @@ -5,7 +5,6 @@ * Copyright 2020 Google LLC. */ -#include #include #include #include diff --git a/drivers/power/supply/cros_usbpd-charger.c b/drivers/power/supply/cros_usbpd-charger.c index 308e1d4e6dd8..c1cbe6e5476e 100644 --- a/drivers/power/supply/cros_usbpd-charger.c +++ b/drivers/power/supply/cros_usbpd-charger.c @@ -5,7 +5,6 @@ * Copyright (c) 2014 - 2018 Google, Inc */ -#include #include #include #include diff --git a/drivers/power/supply/lego_ev3_battery.c b/drivers/power/supply/lego_ev3_battery.c index 28454de05761..582644f4e8b3 100644 --- a/drivers/power/supply/lego_ev3_battery.c +++ b/drivers/power/supply/lego_ev3_battery.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c index b6c3bc0d9ec1..81798f22a037 100644 --- a/drivers/power/supply/max14656_charger_detector.c +++ b/drivers/power/supply/max14656_charger_detector.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index 639dacdb9b31..d409d2f0d383 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/max77759_charger.c b/drivers/power/supply/max77759_charger.c index c606d7bafcb8..41d810bb6744 100644 --- a/drivers/power/supply/max77759_charger.c +++ b/drivers/power/supply/max77759_charger.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/max8971_charger.c b/drivers/power/supply/max8971_charger.c index 49a05858bef8..82f20b89b6b4 100644 --- a/drivers/power/supply/max8971_charger.c +++ b/drivers/power/supply/max8971_charger.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/max8998_charger.c b/drivers/power/supply/max8998_charger.c index b0eda2b51e7f..13071350f318 100644 --- a/drivers/power/supply/max8998_charger.c +++ b/drivers/power/supply/max8998_charger.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/power/supply/mp2629_charger.c b/drivers/power/supply/mp2629_charger.c index d281c1059629..f758d6a7bc8c 100644 --- a/drivers/power/supply/mp2629_charger.c +++ b/drivers/power/supply/mp2629_charger.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/olpc_battery.c b/drivers/power/supply/olpc_battery.c index 202c4fa9b903..17433c58fcd4 100644 --- a/drivers/power/supply/olpc_battery.c +++ b/drivers/power/supply/olpc_battery.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/power/supply/pm8916_bms_vm.c b/drivers/power/supply/pm8916_bms_vm.c index de5d571c03e2..b279f79f302c 100644 --- a/drivers/power/supply/pm8916_bms_vm.c +++ b/drivers/power/supply/pm8916_bms_vm.c @@ -13,7 +13,6 @@ #include #include #include -#include #define PM8916_PERPH_TYPE 0x04 #define PM8916_BMS_VM_TYPE 0x020D diff --git a/drivers/power/supply/pm8916_lbc.c b/drivers/power/supply/pm8916_lbc.c index 6b631012a795..cdc4d78c4219 100644 --- a/drivers/power/supply/pm8916_lbc.c +++ b/drivers/power/supply/pm8916_lbc.c @@ -13,7 +13,6 @@ #include #include #include -#include /* Two bytes: type + subtype */ #define PM8916_PERPH_TYPE 0x04 diff --git a/drivers/power/supply/rt5033_charger.c b/drivers/power/supply/rt5033_charger.c index 536ab29b657d..e545a6e7fad7 100644 --- a/drivers/power/supply/rt5033_charger.c +++ b/drivers/power/supply/rt5033_charger.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c index 44c26fb37a77..de0471e54978 100644 --- a/drivers/power/supply/rt9467-charger.c +++ b/drivers/power/supply/rt9467-charger.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/rt9471.c b/drivers/power/supply/rt9471.c index e7f843f12c98..ca7d426849a7 100644 --- a/drivers/power/supply/rt9471.c +++ b/drivers/power/supply/rt9471.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/rt9756.c b/drivers/power/supply/rt9756.c index f254527be653..a7b7e3fb69b1 100644 --- a/drivers/power/supply/rt9756.c +++ b/drivers/power/supply/rt9756.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/s2mu005-battery.c b/drivers/power/supply/s2mu005-battery.c index 64c57a14ef7d..53de6605b492 100644 --- a/drivers/power/supply/s2mu005-battery.c +++ b/drivers/power/supply/s2mu005-battery.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/power/supply/ug3105_battery.c b/drivers/power/supply/ug3105_battery.c index 0cbf45856fac..cccf7499e129 100644 --- a/drivers/power/supply/ug3105_battery.c +++ b/drivers/power/supply/ug3105_battery.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include "adc-battery-helper.h" diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c index 935da68610c7..402f910f3e25 100644 --- a/drivers/pps/clients/pps-gpio.c +++ b/drivers/pps/clients/pps-gpio.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pps/generators/pps_gen_tio.c b/drivers/pps/generators/pps_gen_tio.c index 9483d126ada0..5088aaf1a63a 100644 --- a/drivers/pps/generators/pps_gen_tio.c +++ b/drivers/pps/generators/pps_gen_tio.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/ptp/ptp_dte.c b/drivers/ptp/ptp_dte.c index 847276c69008..834ecacc7bd3 100644 --- a/drivers/ptp/ptp_dte.c +++ b/drivers/ptp/ptp_dte.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-adp5585.c b/drivers/pwm/pwm-adp5585.c index 806f8d79b0d7..0644ff40f0fb 100644 --- a/drivers/pwm/pwm-adp5585.c +++ b/drivers/pwm/pwm-adp5585.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-airoha.c b/drivers/pwm/pwm-airoha.c index 7236e31d2f17..0cf6b011520a 100644 --- a/drivers/pwm/pwm-airoha.c +++ b/drivers/pwm/pwm-airoha.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-apple.c b/drivers/pwm/pwm-apple.c index 6e58aca2f13c..aa49ca1c30e8 100644 --- a/drivers/pwm/pwm-apple.c +++ b/drivers/pwm/pwm-apple.c @@ -12,7 +12,6 @@ * - When APPLE_PWM_CTRL is set to 0, the output is constant low */ -#include #include #include #include diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 858d36991374..da9954818302 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index 994f89ac43b4..3cc1e4008d29 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -17,7 +17,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pwm/pwm-gpio.c b/drivers/pwm/pwm-gpio.c index 5f4edeb394a9..5644d78dfead 100644 --- a/drivers/pwm/pwm-gpio.c +++ b/drivers/pwm/pwm-gpio.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-intel-lgm.c b/drivers/pwm/pwm-intel-lgm.c index 084c71a0a11b..3ae1324b1cb7 100644 --- a/drivers/pwm/pwm-intel-lgm.c +++ b/drivers/pwm/pwm-intel-lgm.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-keembay.c b/drivers/pwm/pwm-keembay.c index 35b641f3f6ed..2e282e067f36 100644 --- a/drivers/pwm/pwm-keembay.c +++ b/drivers/pwm/pwm-keembay.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 1e614b2a0227..01d471725106 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 653ec9d0c8bf..8b95064b8703 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/pwm/pwm-max7360.c b/drivers/pwm/pwm-max7360.c index 732969303dd7..f920877d1748 100644 --- a/drivers/pwm/pwm-max7360.c +++ b/drivers/pwm/pwm-max7360.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index 80d2fa10919f..156c0c74cd80 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -15,7 +15,6 @@ * input clock (PWMCR_SD is set) and the output is driven to inactive. */ -#include #include #include #include diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 4a07315b0744..e11ecf1fa0f9 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -30,7 +30,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c index 934378d6a002..0dc2e3f809c3 100644 --- a/drivers/pwm/pwm-sl28cpld.c +++ b/drivers/pwm/pwm-sl28cpld.c @@ -35,7 +35,6 @@ #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index 4c76ca5e4cdd..438dbaa3a98f 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-sunplus.c b/drivers/pwm/pwm-sunplus.c index b342b843247b..cc8137f108df 100644 --- a/drivers/pwm/pwm-sunplus.c +++ b/drivers/pwm/pwm-sunplus.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 016c82d65527..149d9e35b78c 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -6,7 +6,6 @@ * Copyright (C) 2010 Alexey Charkov */ -#include #include #include #include diff --git a/drivers/regulator/adp5055-regulator.c b/drivers/regulator/adp5055-regulator.c index 4b004a6b2f84..9ebd52b39235 100644 --- a/drivers/regulator/adp5055-regulator.c +++ b/drivers/regulator/adp5055-regulator.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/regulator/bd71828-regulator.c b/drivers/regulator/bd71828-regulator.c index bd61caa8284a..2ced81df0c02 100644 --- a/drivers/regulator/bd71828-regulator.c +++ b/drivers/regulator/bd71828-regulator.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/regulator/max77541-regulator.c b/drivers/regulator/max77541-regulator.c index f2365930e9a9..09094a270c5a 100644 --- a/drivers/regulator/max77541-regulator.c +++ b/drivers/regulator/max77541-regulator.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/regulator/max77675-regulator.c b/drivers/regulator/max77675-regulator.c index af3eb7174875..fad0844f364e 100644 --- a/drivers/regulator/max77675-regulator.c +++ b/drivers/regulator/max77675-regulator.c @@ -5,7 +5,6 @@ */ #include -#include #include #include #include diff --git a/drivers/regulator/mt6370-regulator.c b/drivers/regulator/mt6370-regulator.c index a4ac4a42c108..6997beb51409 100644 --- a/drivers/regulator/mt6370-regulator.c +++ b/drivers/regulator/mt6370-regulator.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index 9fe539a34786..112eb1c73647 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/regulator/rt4803.c b/drivers/regulator/rt4803.c index c96fb026dc10..34cd3f249ada 100644 --- a/drivers/regulator/rt4803.c +++ b/drivers/regulator/rt4803.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/regulator/rt5739.c b/drivers/regulator/rt5739.c index 5fcddd7c2da7..00706cba9f9e 100644 --- a/drivers/regulator/rt5739.c +++ b/drivers/regulator/rt5739.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/regulator/rt6190-regulator.c b/drivers/regulator/rt6190-regulator.c index 3883440295ed..f2cd9540038d 100644 --- a/drivers/regulator/rt6190-regulator.c +++ b/drivers/regulator/rt6190-regulator.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/regulator/rt8092.c b/drivers/regulator/rt8092.c index 558bd04a2090..2ea4872ad8e0 100644 --- a/drivers/regulator/rt8092.c +++ b/drivers/regulator/rt8092.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/regulator/rtq2208-regulator.c b/drivers/regulator/rtq2208-regulator.c index f669a562f036..4fe111aa018f 100644 --- a/drivers/regulator/rtq2208-regulator.c +++ b/drivers/regulator/rtq2208-regulator.c @@ -9,7 +9,6 @@ #include #include #include -#include /* Register */ #define RTQ2208_REG_GLOBAL_INT1 0x12 diff --git a/drivers/regulator/tps6287x-regulator.c b/drivers/regulator/tps6287x-regulator.c index 7b7d3ae39206..9df104cb6bd2 100644 --- a/drivers/regulator/tps6287x-regulator.c +++ b/drivers/regulator/tps6287x-regulator.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index 8df81ceeb845..00e5c3621fd8 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 4317ec62f18f..a73aa3e0d5c5 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -10,7 +10,6 @@ */ #include -#include #include #include diff --git a/drivers/regulator/vexpress-regulator.c b/drivers/regulator/vexpress-regulator.c index 6687077e9a97..5a2e0143cfdf 100644 --- a/drivers/regulator/vexpress-regulator.c +++ b/drivers/regulator/vexpress-regulator.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c index 4c4e69eb32bb..1a2c0f8a5e9e 100644 --- a/drivers/reset/reset-ath79.c +++ b/drivers/reset/reset-ath79.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/reset/reset-axs10x.c b/drivers/reset/reset-axs10x.c index 115f69e0db33..ea0e6b0b6b4d 100644 --- a/drivers/reset/reset-axs10x.c +++ b/drivers/reset/reset-axs10x.c @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/drivers/reset/reset-bcm6345.c b/drivers/reset/reset-bcm6345.c index 56518f7bfbb3..441d9dd76572 100644 --- a/drivers/reset/reset-bcm6345.c +++ b/drivers/reset/reset-bcm6345.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/reset/reset-eyeq.c b/drivers/reset/reset-eyeq.c index 1a3857983897..7b9ab574bd65 100644 --- a/drivers/reset/reset-eyeq.c +++ b/drivers/reset/reset-eyeq.c @@ -95,7 +95,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/reset/reset-gpio.c b/drivers/reset/reset-gpio.c index 26aa2c3a2e68..bf95296a512e 100644 --- a/drivers/reset/reset-gpio.c +++ b/drivers/reset/reset-gpio.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include diff --git a/drivers/reset/reset-sunplus.c b/drivers/reset/reset-sunplus.c index 58b087433759..c136a1f0767a 100644 --- a/drivers/reset/reset-sunplus.c +++ b/drivers/reset/reset-sunplus.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/reset/reset-tn48m.c b/drivers/reset/reset-tn48m.c index 130027291b6e..177ee5127a1e 100644 --- a/drivers/reset/reset-tn48m.c +++ b/drivers/reset/reset-tn48m.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/reset/starfive/reset-starfive-jh7100.c b/drivers/reset/starfive/reset-starfive-jh7100.c index 2a56f7fd4ba7..b178dc7d958e 100644 --- a/drivers/reset/starfive/reset-starfive-jh7100.c +++ b/drivers/reset/starfive/reset-starfive-jh7100.c @@ -5,7 +5,6 @@ * Copyright (C) 2021 Emil Renner Berthing */ -#include #include #include "reset-starfive-jh71x0.h" diff --git a/drivers/rtc/rtc-88pm886.c b/drivers/rtc/rtc-88pm886.c index 13aa3ae82239..71443ae1bc3b 100644 --- a/drivers/rtc/rtc-88pm886.c +++ b/drivers/rtc/rtc-88pm886.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only #include -#include #include #include diff --git a/drivers/rtc/rtc-cpcap.c b/drivers/rtc/rtc-cpcap.c index c170345ac076..a7db3173d24c 100644 --- a/drivers/rtc/rtc-cpcap.c +++ b/drivers/rtc/rtc-cpcap.c @@ -16,7 +16,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-cros-ec.c b/drivers/rtc/rtc-cros-ec.c index f3ecd017e2f7..f56650899b37 100644 --- a/drivers/rtc/rtc-cros-ec.c +++ b/drivers/rtc/rtc-cros-ec.c @@ -5,7 +5,6 @@ // Author: Stephen Barber #include -#include #include #include #include diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 0707ded5368b..fd3858b6569e 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index dcdcdd06f30d..507c9f22036c 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/drivers/rtc/rtc-fsl-ftm-alarm.c b/drivers/rtc/rtc-fsl-ftm-alarm.c index c8015f04c71f..dcb7ef663a78 100644 --- a/drivers/rtc/rtc-fsl-ftm-alarm.c +++ b/drivers/rtc/rtc-fsl-ftm-alarm.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c index 02608d378495..98fa0f518303 100644 --- a/drivers/rtc/rtc-ftrtc010.c +++ b/drivers/rtc/rtc-ftrtc010.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #define DRV_NAME "rtc-ftrtc010" diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c index 2dcdc77ff646..a1266986dead 100644 --- a/drivers/rtc/rtc-lpc24xx.c +++ b/drivers/rtc/rtc-lpc24xx.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 10cd054fe86f..db3bdb171ff0 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 2494d13fd767..7960d5fa8cf0 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c index 2247dd39ee4b..bc0345db6ed6 100644 --- a/drivers/rtc/rtc-moxart.c +++ b/drivers/rtc/rtc-moxart.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #define GPIO_RTC_RESERVED 0x0C diff --git a/drivers/rtc/rtc-msc313.c b/drivers/rtc/rtc-msc313.c index 6ef9c4efd7c9..912a46c6f17e 100644 --- a/drivers/rtc/rtc-msc313.c +++ b/drivers/rtc/rtc-msc313.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 692c00ff544b..3d857681f760 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -14,7 +14,6 @@ #include #include #include -#include static int mtk_rtc_write_trigger(struct mt6397_rtc *rtc) { diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c index 4cf0cbb31a31..9e17dd09d567 100644 --- a/drivers/rtc/rtc-mt7622.c +++ b/drivers/rtc/rtc-mt7622.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c index 570f27af4732..a07acbbcfaeb 100644 --- a/drivers/rtc/rtc-mxc_v2.c +++ b/drivers/rtc/rtc-mxc_v2.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c index ef913cf8593f..6323b777151f 100644 --- a/drivers/rtc/rtc-r7301.c +++ b/drivers/rtc/rtc-r7301.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-rzn1.c b/drivers/rtc/rtc-rzn1.c index c4ed43735457..305f10a8a85b 100644 --- a/drivers/rtc/rtc-rzn1.c +++ b/drivers/rtc/rtc-rzn1.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 0510dc64c3e2..7a5feceb9ee7 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -13,7 +13,6 @@ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka */ #include -#include #include #include #include diff --git a/drivers/rtc/rtc-ssd202d.c b/drivers/rtc/rtc-ssd202d.c index ed6493260096..72aa02eb86ea 100644 --- a/drivers/rtc/rtc-ssd202d.c +++ b/drivers/rtc/rtc-ssd202d.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 528e32b7d101..f16405c3911c 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-ti-k3.c b/drivers/rtc/rtc-ti-k3.c index e801f5b9d757..8df00319cb6b 100644 --- a/drivers/rtc/rtc-ti-k3.c +++ b/drivers/rtc/rtc-ti-k3.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/rtc/rtc-tps6594.c b/drivers/rtc/rtc-tps6594.c index 2cebd54c2dbf..f89fc3e59be0 100644 --- a/drivers/rtc/rtc-tps6594.c +++ b/drivers/rtc/rtc-tps6594.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index eaeb4a6384d1..ecf121a87f88 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -122,6 +122,9 @@ static int monwrite_new_hdr(struct mon_private *monpriv) kfree(monbuf->data); kfree(monbuf); monbuf = NULL; + } else if (monbuf->hdr.datalen != monhdr->datalen) { + /* Data with buffer reuse must not change its length */ + return -EINVAL; } } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) { if (mon_buf_count >= mon_max_bufs) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 6a7497db5fb9..2d4e00a1e48c 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 28e1007005f2..5d8f63f390a8 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -327,7 +327,6 @@ static int pkey_ioctl_verifyprotk(struct pkey_verifyprotk __user *uvp) { struct pkey_verifyprotk kvp; struct protaeskeytoken *t; - u32 keytype; u8 *tmpbuf; int rc; @@ -341,14 +340,6 @@ static int pkey_ioctl_verifyprotk(struct pkey_verifyprotk __user *uvp) return -EINVAL; } - keytype = pkey_aes_bitsize_to_keytype(8 * kvp.protkey.len); - if (!keytype) { - PKEY_DBF_ERR("%s unknown/unsupported protkey length %u\n", - __func__, kvp.protkey.len); - memzero_explicit(&kvp, sizeof(kvp)); - return -EINVAL; - } - /* build a 'protected key token' from the raw protected key */ tmpbuf = kzalloc(sizeof(*t), GFP_KERNEL); if (!tmpbuf) { @@ -358,7 +349,7 @@ static int pkey_ioctl_verifyprotk(struct pkey_verifyprotk __user *uvp) t = (struct protaeskeytoken *)tmpbuf; t->type = TOKTYPE_NON_CCA; t->version = TOKVER_PROTECTED_KEY; - t->keytype = keytype; + t->keytype = kvp.protkey.type; t->len = kvp.protkey.len; memcpy(t->protkey, kvp.protkey.protkey, kvp.protkey.len); diff --git a/drivers/s390/crypto/vfio_ap_drv.c b/drivers/s390/crypto/vfio_ap_drv.c index fd7394d81880..8e69ed286bb9 100644 --- a/drivers/s390/crypto/vfio_ap_drv.c +++ b/drivers/s390/crypto/vfio_ap_drv.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index d307f40706e8..43871cd89b04 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include "ap_bus.h" #include "zcrypt_api.h" diff --git a/drivers/siox/siox-bus-gpio.c b/drivers/siox/siox-bus-gpio.c index 413d5f92311c..a0b62397e972 100644 --- a/drivers/siox/siox-bus-gpio.c +++ b/drivers/siox/siox-bus-gpio.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c index 3ecc4ce9cfa2..5fdf1fe4edaf 100644 --- a/drivers/soc/fsl/qe/qe.c +++ b/drivers/soc/fsl/qe/qe.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index b99718e25f2f..0dc1a7946050 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/soc/renesas/rzn1_irqmux.c b/drivers/soc/renesas/rzn1_irqmux.c index b50b295f83d7..c3887db7afd1 100644 --- a/drivers/soc/renesas/rzn1_irqmux.c +++ b/drivers/soc/renesas/rzn1_irqmux.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/drivers/soc/sophgo/sg2044-topsys.c b/drivers/soc/sophgo/sg2044-topsys.c index 179f2620b2a9..af0a374f1556 100644 --- a/drivers/soc/sophgo/sg2044-topsys.c +++ b/drivers/soc/sophgo/sg2044-topsys.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index 071cd9620634..78b054d43a42 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 87ae63a7e52d..5b0e9dae231f 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c index ced3a73929e3..01a214c3fa21 100644 --- a/drivers/soc/ti/smartreflex.c +++ b/drivers/soc/ti/smartreflex.c @@ -15,7 +15,6 @@ */ #include -#include #include #include #include diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 0490777fa406..a1e8f87a9399 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c index a05aa36828cb..e73c1bea9059 100644 --- a/drivers/soundwire/bus_type.c +++ b/drivers/soundwire/bus_type.c @@ -2,7 +2,6 @@ // Copyright(c) 2015-17 Intel Corporation. #include -#include #include #include #include diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index b8b62735c893..eb66345a6a42 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c index 2905ec19b838..099eb84a548e 100644 --- a/drivers/soundwire/debugfs.c +++ b/drivers/soundwire/debugfs.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 3575d69ce1c5..30a495abe19e 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include "bus.h" diff --git a/drivers/soundwire/mipi_disco.c b/drivers/soundwire/mipi_disco.c index c69b78cd0b62..fdbf51f2bb77 100644 --- a/drivers/soundwire/mipi_disco.c +++ b/drivers/soundwire/mipi_disco.c @@ -19,7 +19,6 @@ #include #include -#include #include #include "bus.h" diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index cdac009b1a75..5d20e95a1e23 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/soundwire/sysfs_slave.c b/drivers/soundwire/sysfs_slave.c index c5c22d1708ec..a2ee064147e0 100644 --- a/drivers/soundwire/sysfs_slave.c +++ b/drivers/soundwire/sysfs_slave.c @@ -2,7 +2,6 @@ // Copyright(c) 2015-2020 Intel Corporation. #include -#include #include #include #include diff --git a/drivers/soundwire/sysfs_slave_dpn.c b/drivers/soundwire/sysfs_slave_dpn.c index a3fb380ee519..d2561400da77 100644 --- a/drivers/soundwire/sysfs_slave_dpn.c +++ b/drivers/soundwire/sysfs_slave_dpn.c @@ -2,7 +2,6 @@ // Copyright(c) 2015-2020 Intel Corporation. #include -#include #include #include #include diff --git a/drivers/spi/spi-atcspi200.c b/drivers/spi/spi-atcspi200.c index 6d4b6aeb3f5b..3c5098421ba3 100644 --- a/drivers/spi/spi-atcspi200.c +++ b/drivers/spi/spi-atcspi200.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 6961e36b89d1..7106a8a4f280 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c index eff08461c2f5..ad8aad958c76 100644 --- a/drivers/spi/spi-dw-core.c +++ b/drivers/spi/spi-dw-core.c @@ -949,7 +949,7 @@ int dw_spi_add_controller(struct device *dev, struct dw_spi *dws) ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), ctlr); if (ret < 0 && ret != -ENOTCONN) { - dev_err(dev, "can not get IRQ\n"); + dev_err(dev, "can not request IRQ\n"); goto err_free_ctlr; } diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c index fe726b9b1780..bd70a7ed8067 100644 --- a/drivers/spi/spi-dw-dma.c +++ b/drivers/spi/spi-dw-dma.c @@ -247,11 +247,12 @@ static bool dw_spi_can_dma(struct spi_controller *ctlr, { struct dw_spi *dws = spi_controller_get_devdata(ctlr); enum dma_slave_buswidth dma_bus_width; + u8 n_bytes = roundup_pow_of_two(BITS_TO_BYTES(xfer->bits_per_word)); if (xfer->len <= dws->fifo_len) return false; - dma_bus_width = dw_spi_dma_convert_width(dws->n_bytes); + dma_bus_width = dw_spi_dma_convert_width(n_bytes); return dws->dma_addr_widths & BIT(dma_bus_width); } diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 072127a38fad..c32c33b27e1a 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -7,7 +7,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/spi/spi-hisi-sfc-v3xx.c b/drivers/spi/spi-hisi-sfc-v3xx.c index eeeb86381862..d60db579b0fb 100644 --- a/drivers/spi/spi-hisi-sfc-v3xx.c +++ b/drivers/spi/spi-hisi-sfc-v3xx.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-loongson-pci.c b/drivers/spi/spi-loongson-pci.c index cbcde153260e..2fe5419a8dd2 100644 --- a/drivers/spi/spi-loongson-pci.c +++ b/drivers/spi/spi-loongson-pci.c @@ -2,7 +2,6 @@ // PCI interface driver for Loongson SPI Support // Copyright (C) 2023 Loongson Technology Corporation Limited -#include #include #include "spi-loongson.h" diff --git a/drivers/spi/spi-loongson-plat.c b/drivers/spi/spi-loongson-plat.c index 64a7270f9a64..550b237838c0 100644 --- a/drivers/spi/spi-loongson-plat.c +++ b/drivers/spi/spi-loongson-plat.c @@ -3,7 +3,6 @@ // Copyright (C) 2023 Loongson Technology Corporation Limited #include -#include #include #include "spi-loongson.h" diff --git a/drivers/spi/spi-loopback-test.c b/drivers/spi/spi-loopback-test.c index e0b131aa29b6..066386abadac 100644 --- a/drivers/spi/spi-loopback-test.c +++ b/drivers/spi/spi-loopback-test.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c b/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c index 8468c773713a..c4c25c2cc4b5 100644 --- a/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c +++ b/drivers/spi/spi-offload-trigger-adi-util-sigma-delta.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-offload-trigger-pwm.c b/drivers/spi/spi-offload-trigger-pwm.c index 3e8c19227edb..0eff14328a6b 100644 --- a/drivers/spi/spi-offload-trigger-pwm.c +++ b/drivers/spi/spi-offload-trigger-pwm.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-pxa2xx-platform.c b/drivers/spi/spi-pxa2xx-platform.c index 45e159e75a52..849a14cd0343 100644 --- a/drivers/spi/spi-pxa2xx-platform.c +++ b/drivers/spi/spi-pxa2xx-platform.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-realtek-rtl-snand.c b/drivers/spi/spi-realtek-rtl-snand.c index 7d5853d202c6..61fe54d8167a 100644 --- a/drivers/spi/spi-realtek-rtl-snand.c +++ b/drivers/spi/spi-realtek-rtl-snand.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-realtek-rtl.c b/drivers/spi/spi-realtek-rtl.c index d7acc02105ca..73065c8934dc 100644 --- a/drivers/spi/spi-realtek-rtl.c +++ b/drivers/spi/spi-realtek-rtl.c @@ -2,7 +2,6 @@ #include #include -#include #include struct rtspi { diff --git a/drivers/spi/spi-rzv2h-rspi.c b/drivers/spi/spi-rzv2h-rspi.c index 0738d448160d..daa4239b0fe0 100644 --- a/drivers/spi/spi-rzv2h-rspi.c +++ b/drivers/spi/spi-rzv2h-rspi.c @@ -366,14 +366,14 @@ static int rzv2h_rspi_transfer_dma(struct rzv2h_rspi_priv *rspi, rzv2h_rspi_clear_all_irqs(rspi); ret = wait_event_interruptible_timeout(rspi->wait, rspi->dma_callbacked, HZ); - if (ret) { + if (ret > 0) { dmaengine_synchronize(rspi->controller->dma_tx); dmaengine_synchronize(rspi->controller->dma_rx); ret = 0; } else { dmaengine_terminate_sync(rspi->controller->dma_tx); dmaengine_terminate_sync(rspi->controller->dma_rx); - ret = -ETIMEDOUT; + ret = ret ?: -ETIMEDOUT; } enable_irq(rspi->irq_rx); diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index ae534ebd5e87..ebd5c172efda 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index f23db85a1889..1aeab7ec0bc8 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -114,7 +114,7 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data) return IRQ_HANDLED; } -static void sh_msiof_spi_reset_regs(struct sh_msiof_spi_priv *p) +static int sh_msiof_spi_reset_regs(struct sh_msiof_spi_priv *p) { u32 mask = SICTR_TXRST | SICTR_RXRST; u32 data; @@ -123,8 +123,8 @@ static void sh_msiof_spi_reset_regs(struct sh_msiof_spi_priv *p) data |= mask; sh_msiof_write(p, SICTR, data); - readl_poll_timeout_atomic(p->mapbase + SICTR, data, !(data & mask), 1, - 100); + return readl_poll_timeout_atomic(p->mapbase + SICTR, data, + !(data & mask), 1, 100); } static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, @@ -834,7 +834,9 @@ static int sh_msiof_transfer_one(struct spi_controller *ctlr, int ret; /* reset registers */ - sh_msiof_spi_reset_regs(p); + ret = sh_msiof_spi_reset_regs(p); + if (ret) + return ret; /* setup clocks (clock already enabled in chipselect()) */ if (!spi_controller_is_target(p->ctlr)) diff --git a/drivers/spi/spi-wpcm-fiu.c b/drivers/spi/spi-wpcm-fiu.c index cd78e927953d..884e5042bad5 100644 --- a/drivers/spi/spi-wpcm-fiu.c +++ b/drivers/spi/spi-wpcm-fiu.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index f897789a44d1..d9e6b4b87c89 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -3671,6 +3670,9 @@ int spi_controller_suspend(struct spi_controller *ctlr) { int ret = 0; + if (ctlr->cur_msg && spi_controller_is_target(ctlr) && ctlr->target_abort) + ctlr->target_abort(ctlr); + /* Basically no-ops for non-queued controllers */ if (ctlr->queued) { ret = spi_stop_queue(ctlr); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 638221178384..15d2aaeb08e9 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spmi/spmi-apple-controller.c b/drivers/spmi/spmi-apple-controller.c index 87e3ee9d4f2a..376cf682c43e 100644 --- a/drivers/spmi/spmi-apple-controller.c +++ b/drivers/spmi/spmi-apple-controller.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/greybus/arche-apb-ctrl.c b/drivers/staging/greybus/arche-apb-ctrl.c index 19a6e59b6d5c..4302c2226126 100644 --- a/drivers/staging/greybus/arche-apb-ctrl.c +++ b/drivers/staging/greybus/arche-apb-ctrl.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "arche_platform.h" static void apb_bootret_deassert(struct device *dev); diff --git a/drivers/staging/iio/frequency/ad9832.c b/drivers/staging/iio/frequency/ad9832.c index 659821a1e2cb..60c33e10c46f 100644 --- a/drivers/staging/iio/frequency/ad9832.c +++ b/drivers/staging/iio/frequency/ad9832.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 4359b358e0e5..33dfd723923c 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/thermal/loongson2_thermal.c b/drivers/thermal/loongson2_thermal.c index ea4dd2fb1f47..88f87badfdf6 100644 --- a/drivers/thermal/loongson2_thermal.c +++ b/drivers/thermal/loongson2_thermal.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/thermal/renesas/rzg2l_thermal.c b/drivers/thermal/renesas/rzg2l_thermal.c index b588be628640..d9afd0619167 100644 --- a/drivers/thermal/renesas/rzg2l_thermal.c +++ b/drivers/thermal/renesas/rzg2l_thermal.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 12d08de59095..16edd71a0d8d 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/8250/8250_dfl.c b/drivers/tty/serial/8250/8250_dfl.c index 6c5ff019df4b..475ca340948c 100644 --- a/drivers/tty/serial/8250/8250_dfl.c +++ b/drivers/tty/serial/8250/8250_dfl.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 84ffba045ffa..5fba913f3301 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c index e90c71494944..32d077da076a 100644 --- a/drivers/tty/serial/8250/8250_em.c +++ b/drivers/tty/serial/8250/8250_em.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c index f94d97e69dc5..5b791b6eefd0 100644 --- a/drivers/tty/serial/8250/8250_keba.c +++ b/drivers/tty/serial/8250/8250_keba.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c index 47df3c4c9d21..19acb2c6b611 100644 --- a/drivers/tty/serial/8250/8250_loongson.c +++ b/drivers/tty/serial/8250/8250_loongson.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c index 0935341dd050..9f945f8ed1de 100644 --- a/drivers/tty/serial/8250/8250_ni.c +++ b/drivers/tty/serial/8250/8250_ni.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c index 475b0a6efce4..44b745fa26c6 100644 --- a/drivers/tty/serial/max3100.c +++ b/drivers/tty/serial/max3100.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index e28e3065c99d..59e71306a5d4 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 1fd64a47341d..daebd92f32c7 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c index 6c2a697556a6..bc27d931def2 100644 --- a/drivers/tty/serial/sc16is7xx_i2c.c +++ b/drivers/tty/serial/sc16is7xx_i2c.c @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c index 7e76d0e38da7..96fde93ae446 100644 --- a/drivers/tty/serial/sc16is7xx_spi.c +++ b/drivers/tty/serial/sc16is7xx_spi.c @@ -2,7 +2,6 @@ /* SC16IS7xx SPI interface driver */ #include -#include #include #include #include diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 4ceca11ce600..cb31e3aceb62 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c index 0c70d3e7b9b9..3d43c11824ca 100644 --- a/drivers/tty/serial/tegra-utc.c +++ b/drivers/tty/serial/tegra-utc.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/uio/uio_pdrv_genirq.c b/drivers/uio/uio_pdrv_genirq.c index 0a1885d1b2e3..0c8d73e7be52 100644 --- a/drivers/uio/uio_pdrv_genirq.c +++ b/drivers/uio/uio_pdrv_genirq.c @@ -23,7 +23,6 @@ #include #include -#include #include #define DRIVER_NAME "uio_pdrv_genirq" diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 34127b890b2a..767251aa1aa3 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -9,6 +9,7 @@ #define __DWC2_CORE_H__ #include +#include #include #include #include diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c index 5d510665da1f..d67002ea049a 100644 --- a/drivers/usb/gadget/udc/renesas_usbf.c +++ b/drivers/usb/gadget/udc/renesas_usbf.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/misc/usb-ljca.c b/drivers/usb/misc/usb-ljca.c index c60121faa3da..78e94dd89da5 100644 --- a/drivers/usb/misc/usb-ljca.c +++ b/drivers/usb/misc/usb-ljca.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/typec/mux/tusb1046.c b/drivers/usb/typec/mux/tusb1046.c index 3c1a4551c2fb..d6e1289a4945 100644 --- a/drivers/usb/typec/mux/tusb1046.c +++ b/drivers/usb/typec/mux/tusb1046.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c index 35320f89dad2..d770e58bc16c 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c index c8b1463e6e8b..e6b28648f440 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c index 8fac171778da..01b310549c8c 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_pdphy_stub.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c index 429bd42a0e62..bf985efe1cd6 100644 --- a/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c +++ b/drivers/usb/typec/tcpm/qcom/qcom_pmic_typec_port.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/typec/tcpm/tcpci_mt6370.c b/drivers/usb/typec/tcpm/tcpci_mt6370.c index ed822f438a09..7d6c75c70985 100644 --- a/drivers/usb/typec/tcpm/tcpci_mt6370.c +++ b/drivers/usb/typec/tcpm/tcpci_mt6370.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/typec/tcpm/tcpci_rt1711h.c b/drivers/usb/typec/tcpm/tcpci_rt1711h.c index a8726da6fc71..9d3b1fcf7e27 100644 --- a/drivers/usb/typec/tcpm/tcpci_rt1711h.c +++ b/drivers/usb/typec/tcpm/tcpci_rt1711h.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/usb/typec/ucsi/cros_ec_ucsi.c b/drivers/usb/typec/ucsi/cros_ec_ucsi.c index c192d42d449e..c38eb678d5fe 100644 --- a/drivers/usb/typec/ucsi/cros_ec_ucsi.c +++ b/drivers/usb/typec/ucsi/cros_ec_ucsi.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/vdpa/vdpa.c b/drivers/vdpa/vdpa.c index caf0ee5d6856..47c6c3d23f5c 100644 --- a/drivers/vdpa/vdpa.c +++ b/drivers/vdpa/vdpa.c @@ -13,7 +13,6 @@ #include #include #include -#include #include static LIST_HEAD(mdev_head); diff --git a/drivers/vdpa/vdpa_user/vduse_dev.c b/drivers/vdpa/vdpa_user/vduse_dev.c index f15ad425e01f..10dcf016bfb0 100644 --- a/drivers/vdpa/vdpa_user/vduse_dev.c +++ b/drivers/vdpa/vdpa_user/vduse_dev.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "iova_domain.h" diff --git a/drivers/vfio/debugfs.c b/drivers/vfio/debugfs.c index 8b0ca7a09064..8a2f1b0cce3f 100644 --- a/drivers/vfio/debugfs.c +++ b/drivers/vfio/debugfs.c @@ -97,6 +97,7 @@ void vfio_device_debugfs_init(struct vfio_device *vdev) void vfio_device_debugfs_exit(struct vfio_device *vdev) { debugfs_remove_recursive(vdev->debug_root); + vdev->debug_root = NULL; } void vfio_debugfs_create_root(void) diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h index deed0f132f39..c86d8b243a52 100644 --- a/drivers/vfio/pci/mlx5/cmd.h +++ b/drivers/vfio/pci/mlx5/cmd.h @@ -158,26 +158,29 @@ struct mlx5_vhca_qp { struct mlx5_vhca_page_tracker { u32 id; u32 pdn; - u8 is_err:1; - u8 object_changed:1; + /* Flags modified at runtime - dedicated storage unit */ + u8 is_err; + u8 object_changed; + int status; struct mlx5_uars_page *uar; struct mlx5_vhca_cq cq; struct mlx5_vhca_qp *host_qp; struct mlx5_vhca_qp *fw_qp; struct mlx5_nb nb; - int status; }; struct mlx5vf_pci_core_device { struct vfio_pci_core_device core_device; int vf_id; u16 vhca_id; + /* Flags only modified on setup/release - bitfield ok */ u8 migrate_cap:1; - u8 deferred_reset:1; - u8 mdev_detach:1; - u8 log_active:1; u8 chunk_mode:1; u8 mig_state_cap:1; + /* Flags modified at runtime - dedicated storage unit */ + u8 mdev_detach; + u8 log_active; + u8 deferred_reset; struct completion tracker_comp; /* protect migration state */ struct mutex state_mutex; diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index 0c771064c0b8..830369ff878d 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -125,9 +125,30 @@ static int vfio_pci_open_device(struct vfio_device *core_vdev) return 0; } +static int vfio_pci_init_dev(struct vfio_device *core_vdev) +{ + struct vfio_pci_core_device *vdev = + container_of(core_vdev, struct vfio_pci_core_device, vdev); + + /* + * These behaviors originated in vfio-pci and moved into + * vfio-pci-core when the driver was split; vfio-pci remains the + * only driver that toggles them. Latch our module parameters per + * device at init time so that later parameter changes do not + * affect already-initialized devices. + */ + vdev->nointxmask = nointxmask; + vdev->disable_idle_d3 = disable_idle_d3; +#ifdef CONFIG_VFIO_PCI_VGA + vdev->disable_vga = disable_vga; +#endif + + return vfio_pci_core_init_dev(core_vdev); +} + static const struct vfio_device_ops vfio_pci_ops = { .name = "vfio-pci", - .init = vfio_pci_core_init_dev, + .init = vfio_pci_init_dev, .release = vfio_pci_core_release_dev, .open_device = vfio_pci_open_device, .close_device = vfio_pci_core_close_device, @@ -256,13 +277,6 @@ static void __init vfio_pci_fill_ids(void) static int __init vfio_pci_init(void) { int ret; - bool is_disable_vga = true; - -#ifdef CONFIG_VFIO_PCI_VGA - is_disable_vga = disable_vga; -#endif - - vfio_pci_core_set_params(nointxmask, is_disable_vga, disable_idle_d3); /* Register and scan for devices */ ret = pci_register_driver(&vfio_pci_driver); diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c index a28f1e99362c..3f11a9624b9c 100644 --- a/drivers/vfio/pci/vfio_pci_core.c +++ b/drivers/vfio/pci/vfio_pci_core.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #if IS_ENABLED(CONFIG_EEH) #include #endif @@ -38,10 +40,6 @@ #define DRIVER_AUTHOR "Alex Williamson " #define DRIVER_DESC "core driver for VFIO based PCI devices" -static bool nointxmask; -static bool disable_vga; -static bool disable_idle_d3; - static void vfio_pci_eventfd_rcu_free(struct rcu_head *rcu) { struct vfio_pci_eventfd *eventfd = @@ -92,15 +90,69 @@ struct vfio_pci_vf_token { int users; }; -static inline bool vfio_vga_disabled(void) +static inline bool vfio_vga_disabled(struct vfio_pci_core_device *vdev) { #ifdef CONFIG_VFIO_PCI_VGA - return disable_vga; + return vdev->disable_vga; #else return true; #endif } +#ifdef CONFIG_VFIO_DEBUGFS +static struct vfio_pci_core_device * +vfio_pci_core_debugfs_private(struct seq_file *seq) +{ + struct device *dev = seq->private; + struct vfio_device *core_vdev = container_of(dev, struct vfio_device, + device); + + return container_of(core_vdev, struct vfio_pci_core_device, vdev); +} + +static int vfio_pci_core_debugfs_nointxmask(struct seq_file *seq, void *data) +{ + struct vfio_pci_core_device *vdev = vfio_pci_core_debugfs_private(seq); + + seq_puts(seq, vdev->nointxmask ? "Y\n" : "N\n"); + return 0; +} + +static int vfio_pci_core_debugfs_disable_idle_d3(struct seq_file *seq, + void *data) +{ + struct vfio_pci_core_device *vdev = vfio_pci_core_debugfs_private(seq); + + seq_puts(seq, vdev->disable_idle_d3 ? "Y\n" : "N\n"); + return 0; +} + +/* + * disable_idle_d3 and nointxmask are writable module parameters latched + * per device at init, so a device's effective value can differ from the + * current parameter setting. Expose the per-device (read-only) values + * here for visibility; read-only parameters can't drift and are omitted. + */ +static void vfio_pci_core_debugfs_init(struct vfio_pci_core_device *vdev) +{ + struct device *dev = &vdev->vdev.device; + struct dentry *pci_dir; + + if (IS_ERR_OR_NULL(vdev->vdev.debug_root)) + return; + + pci_dir = debugfs_create_dir("pci", vdev->vdev.debug_root); + debugfs_create_devm_seqfile(dev, "nointxmask", pci_dir, + vfio_pci_core_debugfs_nointxmask); + debugfs_create_devm_seqfile(dev, "disable_idle_d3", pci_dir, + vfio_pci_core_debugfs_disable_idle_d3); +} +#else +static inline void vfio_pci_core_debugfs_init(struct vfio_pci_core_device *vdev) +{ +} +#endif /* CONFIG_VFIO_DEBUGFS */ + /* * Our VGA arbiter participation is limited since we don't know anything * about the device itself. However, if the device is the only VGA device @@ -111,11 +163,12 @@ static inline bool vfio_vga_disabled(void) */ static unsigned int vfio_pci_set_decode(struct pci_dev *pdev, bool single_vga) { + struct vfio_pci_core_device *vdev = dev_get_drvdata(&pdev->dev); struct pci_dev *tmp = NULL; unsigned char max_busnr; unsigned int decodes; - if (single_vga || !vfio_vga_disabled() || pci_is_root_bus(pdev->bus)) + if (single_vga || !vfio_vga_disabled(vdev) || pci_is_root_bus(pdev->bus)) return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM | VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM; @@ -538,7 +591,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) u16 cmd; u8 msix_pos; - if (!disable_idle_d3) { + if (!vdev->disable_idle_d3) { ret = pm_runtime_resume_and_get(&pdev->dev); if (ret < 0) return ret; @@ -562,7 +615,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) if (!vdev->pci_saved_state) pci_dbg(pdev, "%s: Couldn't store saved state\n", __func__); - if (likely(!nointxmask)) { + if (likely(!vdev->nointxmask)) { if (vfio_pci_nointx(pdev)) { pci_info(pdev, "Masking broken INTx support\n"); vdev->nointx = true; @@ -602,7 +655,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) vdev->has_dyn_msix = false; } - if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev)) + if (!vfio_vga_disabled(vdev) && vfio_pci_is_vga(pdev)) vdev->has_vga = true; vfio_pci_core_map_bars(vdev); @@ -617,7 +670,7 @@ int vfio_pci_core_enable(struct vfio_pci_core_device *vdev) out_disable_device: pci_disable_device(pdev); out_power: - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_put(&pdev->dev); return ret; } @@ -753,7 +806,7 @@ void vfio_pci_core_disable(struct vfio_pci_core_device *vdev) vfio_pci_dev_set_try_reset(vdev->vdev.dev_set); /* Put the pm-runtime usage counter acquired during enable */ - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_put(&pdev->dev); } EXPORT_SYMBOL_GPL(vfio_pci_core_disable); @@ -2239,19 +2292,23 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev) dev->driver->pm = &vfio_pci_core_pm_ops; pm_runtime_allow(dev); - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_put(dev); ret = vfio_register_group_dev(&vdev->vdev); if (ret) goto out_power; + + vfio_pci_core_debugfs_init(vdev); + return 0; out_power: - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_get_noresume(dev); pm_runtime_forbid(dev); + vfio_pci_vga_uninit(vdev); out_vf: vfio_pci_vf_uninit(vdev); return ret; @@ -2267,7 +2324,7 @@ void vfio_pci_core_unregister_device(struct vfio_pci_core_device *vdev) vfio_pci_vf_uninit(vdev); vfio_pci_vga_uninit(vdev); - if (!disable_idle_d3) + if (!vdev->disable_idle_d3) pm_runtime_get_noresume(&vdev->pdev->dev); pm_runtime_forbid(&vdev->pdev->dev); @@ -2599,7 +2656,7 @@ static void vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set) * state. Increment the usage count for all the devices in the dev_set * before reset and decrement the same after reset. */ - if (!disable_idle_d3 && vfio_pci_dev_set_pm_runtime_get(dev_set)) + if (vfio_pci_dev_set_pm_runtime_get(dev_set)) return; if (!pci_reset_bus(pdev)) @@ -2609,20 +2666,10 @@ static void vfio_pci_dev_set_try_reset(struct vfio_device_set *dev_set) if (reset_done) cur->needs_reset = false; - if (!disable_idle_d3) - pm_runtime_put(&cur->pdev->dev); + pm_runtime_put(&cur->pdev->dev); } } -void vfio_pci_core_set_params(bool is_nointxmask, bool is_disable_vga, - bool is_disable_idle_d3) -{ - nointxmask = is_nointxmask; - disable_vga = is_disable_vga; - disable_idle_d3 = is_disable_idle_d3; -} -EXPORT_SYMBOL_GPL(vfio_pci_core_set_params); - static void vfio_pci_core_cleanup(void) { vfio_pci_uninit_perm_bits(); diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 5e0422014523..ed538aebb0b8 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -406,6 +406,13 @@ void vfio_unregister_group_dev(struct vfio_device *device) */ vfio_device_group_unregister(device); + /* + * Remove debugfs before device_del(), which releases devres. Some + * debugfs entries are created with debugfs_create_devm_seqfile() and + * therefore rely on devres-managed inode private data. + */ + vfio_device_debugfs_exit(device); + /* * Balances vfio_device_add() in register path, also prevents * new device opened by userspace in the cdev path. @@ -435,7 +442,6 @@ void vfio_unregister_group_dev(struct vfio_device *device) } } - vfio_device_debugfs_exit(device); /* Balances vfio_device_set_group in register path */ vfio_device_remove_group(device); } diff --git a/drivers/video/backlight/apple_dwi_bl.c b/drivers/video/backlight/apple_dwi_bl.c index ed8bf13d3f51..93bd744972d6 100644 --- a/drivers/video/backlight/apple_dwi_bl.c +++ b/drivers/video/backlight/apple_dwi_bl.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c index 2493138febfa..f41523d78121 100644 --- a/drivers/video/backlight/da9052_bl.c +++ b/drivers/video/backlight/da9052_bl.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c index 61a57d38700f..590365c6a51b 100644 --- a/drivers/video/backlight/hx8357.c +++ b/drivers/video/backlight/hx8357.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/backlight/ktd2801-backlight.c b/drivers/video/backlight/ktd2801-backlight.c index 1b1307e03b20..02baf3a60b2a 100644 --- a/drivers/video/backlight/ktd2801-backlight.c +++ b/drivers/video/backlight/ktd2801-backlight.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/drivers/video/backlight/mp3309c.c b/drivers/video/backlight/mp3309c.c index 413cfe27dfd9..752a45798bfc 100644 --- a/drivers/video/backlight/mp3309c.c +++ b/drivers/video/backlight/mp3309c.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/backlight/mt6370-backlight.c b/drivers/video/backlight/mt6370-backlight.c index e55f26888d0f..7905372c2a4c 100644 --- a/drivers/video/backlight/mt6370-backlight.c +++ b/drivers/video/backlight/mt6370-backlight.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/backlight/rave-sp-backlight.c b/drivers/video/backlight/rave-sp-backlight.c index bfe01b9b9174..b7528ef02119 100644 --- a/drivers/video/backlight/rave-sp-backlight.c +++ b/drivers/video/backlight/rave-sp-backlight.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/video/backlight/rt4831-backlight.c b/drivers/video/backlight/rt4831-backlight.c index 26214519bfce..7ead75929a43 100644 --- a/drivers/video/backlight/rt4831-backlight.c +++ b/drivers/video/backlight/rt4831-backlight.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c index f4e7ed943b8a..8423d90313da 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-opa362.c @@ -13,7 +13,6 @@ #include #include -#include #include #include diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c index 458e65771cbb..881c8f1ad7a8 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tfp410.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c index 8cf0cb922f3c..635375e9080c 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c index 1d75f27c6b80..5e7963b4aa93 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-dsi-cm.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c index 66d00b6ceb78..32cd038cb79b 100644 --- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c +++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c index a9ecc46df187..d0303e31e816 100644 --- a/drivers/virt/coco/tdx-guest/tdx-guest.c +++ b/drivers/virt/coco/tdx-guest/tdx-guest.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c index d48952968e86..e8ed8dfa526e 100644 --- a/drivers/virt/coco/tdx-host/tdx-host.c +++ b/drivers/virt/coco/tdx-host/tdx-host.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/w1/masters/amd_axi_w1.c b/drivers/w1/masters/amd_axi_w1.c index 5da8b8d86811..96d986e0f58d 100644 --- a/drivers/w1/masters/amd_axi_w1.c +++ b/drivers/w1/masters/amd_axi_w1.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c index aa1f57f74397..3cbff88c339e 100644 --- a/drivers/w1/masters/ds2490.c +++ b/drivers/w1/masters/ds2490.c @@ -7,7 +7,6 @@ #include #include -#include #include #include diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index 30a190ce4298..761dcbdd732a 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/drivers/w1/masters/sgi_w1.c b/drivers/w1/masters/sgi_w1.c index af6b1186b763..48c10062022c 100644 --- a/drivers/w1/masters/sgi_w1.c +++ b/drivers/w1/masters/sgi_w1.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index a579f95be8f1..184aea37bfaf 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 1795aaf1ec45..d5afcc634221 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/cros_ec_wdt.c b/drivers/watchdog/cros_ec_wdt.c index 9ffe7f505645..9a4a59b39ed9 100644 --- a/drivers/watchdog/cros_ec_wdt.c +++ b/drivers/watchdog/cros_ec_wdt.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 5f2184bda7b2..6ea0434f45c2 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/watchdog/ftwdt010_wdt.c b/drivers/watchdog/ftwdt010_wdt.c index 28f5af752c10..67f16b34a25f 100644 --- a/drivers/watchdog/ftwdt010_wdt.c +++ b/drivers/watchdog/ftwdt010_wdt.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index a7b814ea740b..1abc7d0b78a6 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/gunyah_wdt.c b/drivers/watchdog/gunyah_wdt.c index 49dfef459e84..557a78306d18 100644 --- a/drivers/watchdog/gunyah_wdt.c +++ b/drivers/watchdog/gunyah_wdt.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index a55f801895d4..65cc8396aa59 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/keembay_wdt.c b/drivers/watchdog/keembay_wdt.c index 2a39114dbc64..3854249c7455 100644 --- a/drivers/watchdog/keembay_wdt.c +++ b/drivers/watchdog/keembay_wdt.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c index 21935f9620e4..3b4f3134d1c4 100644 --- a/drivers/watchdog/max63xx_wdt.c +++ b/drivers/watchdog/max63xx_wdt.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/max77620_wdt.c b/drivers/watchdog/max77620_wdt.c index d3ced783a5f4..6ce435741d97 100644 --- a/drivers/watchdog/max77620_wdt.c +++ b/drivers/watchdog/max77620_wdt.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c index 497496f64f55..44db4ebc8599 100644 --- a/drivers/watchdog/meson_wdt.c +++ b/drivers/watchdog/meson_wdt.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/moxart_wdt.c b/drivers/watchdog/moxart_wdt.c index b7b1da3c932d..1b68a1917003 100644 --- a/drivers/watchdog/moxart_wdt.c +++ b/drivers/watchdog/moxart_wdt.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/msc313e_wdt.c b/drivers/watchdog/msc313e_wdt.c index 90171431fc59..d962589e2c55 100644 --- a/drivers/watchdog/msc313e_wdt.c +++ b/drivers/watchdog/msc313e_wdt.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index 442731bba194..db47b131f780 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c index 44b5298f599a..8169423801f0 100644 --- a/drivers/watchdog/nic7018_wdt.c +++ b/drivers/watchdog/nic7018_wdt.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index d523428a8d22..95c7e44b7baa 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -27,7 +27,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include diff --git a/drivers/watchdog/pseries-wdt.c b/drivers/watchdog/pseries-wdt.c index 7f53b5293409..48d67f7c972a 100644 --- a/drivers/watchdog/pseries-wdt.c +++ b/drivers/watchdog/pseries-wdt.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/realtek_otto_wdt.c b/drivers/watchdog/realtek_otto_wdt.c index 01b3ef89bacf..9094f2189f55 100644 --- a/drivers/watchdog/realtek_otto_wdt.c +++ b/drivers/watchdog/realtek_otto_wdt.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 4499ba0eb5ea..c8edd83bb502 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c @@ -15,7 +15,6 @@ #include #include #include -#include #include diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index c3c7715140ea..7c1bd83b056a 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index 13933e12b754..e04d42cc7774 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/sl28cpld_wdt.c b/drivers/watchdog/sl28cpld_wdt.c index 8630c29818f2..c0b5e5fff5d7 100644 --- a/drivers/watchdog/sl28cpld_wdt.c +++ b/drivers/watchdog/sl28cpld_wdt.c @@ -6,7 +6,6 @@ */ #include -#include #include #include #include diff --git a/drivers/watchdog/sunplus_wdt.c b/drivers/watchdog/sunplus_wdt.c index 9d3ca848e8b6..ae0c11a15a05 100644 --- a/drivers/watchdog/sunplus_wdt.c +++ b/drivers/watchdog/sunplus_wdt.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index ac709dc31a65..ede46a442b94 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 8c80d04811e4..69a622646d75 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/watchdog/xilinx_wwdt.c b/drivers/watchdog/xilinx_wwdt.c index 3d2a156f7180..799ce8d22b2f 100644 --- a/drivers/watchdog/xilinx_wwdt.c +++ b/drivers/watchdog/xilinx_wwdt.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index eadedd1e963e..3218686be45b 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -70,14 +70,14 @@ #include #include -static int limit = 1024; -module_param(limit, int, 0644); +static unsigned int limit = 1024; +module_param(limit, uint, 0644); MODULE_PARM_DESC(limit, "Maximum number of grants that may be allocated by " "the gntalloc device"); static LIST_HEAD(gref_list); static DEFINE_MUTEX(gref_mutex); -static int gref_size; +static unsigned int gref_size; struct notify_info { uint16_t pgoff:12; /* Bits 0-11: Offset of the byte to clear */ @@ -272,6 +272,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv, int rc = 0; struct ioctl_gntalloc_alloc_gref op; uint32_t *gref_ids; + unsigned int limit_snapshot; pr_debug("%s: priv %p\n", __func__, priv); @@ -280,6 +281,12 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv, goto out; } + limit_snapshot = READ_ONCE(limit); + if (op.count > limit_snapshot) { + rc = -ENOSPC; + goto out; + } + gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_KERNEL); if (!gref_ids) { rc = -ENOMEM; @@ -292,14 +299,16 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv, * are about to enforce, removing them here is a good idea. */ do_cleanup(); - if (gref_size + op.count > limit) { + limit_snapshot = READ_ONCE(limit); + if (gref_size > limit_snapshot || + op.count > limit_snapshot - gref_size) { mutex_unlock(&gref_mutex); rc = -ENOSPC; goto out_free; } gref_size += op.count; op.index = priv->index; - priv->index += op.count * PAGE_SIZE; + priv->index += (uint64_t)op.count * PAGE_SIZE; mutex_unlock(&gref_mutex); rc = add_grefs(&op, gref_ids, priv); diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 61ea855c4508..1dcc4675580e 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -670,11 +670,15 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv, mutex_lock(&priv->lock); gntdev_add_map(priv, map); op.index = map->index << PAGE_SHIFT; - mutex_unlock(&priv->lock); - if (copy_to_user(u, &op, sizeof(op)) != 0) + if (copy_to_user(u, &op, sizeof(op)) != 0) { + list_del(&map->next); + mutex_unlock(&priv->lock); + gntdev_put_map(priv, map); return -EFAULT; + } + mutex_unlock(&priv->lock); return 0; } diff --git a/drivers/xen/pvcalls-front.c b/drivers/xen/pvcalls-front.c index 50ce4820f7ee..3e7aa807c317 100644 --- a/drivers/xen/pvcalls-front.c +++ b/drivers/xen/pvcalls-front.c @@ -32,6 +32,7 @@ struct pvcalls_bedata { struct xen_pvcalls_front_ring ring; grant_ref_t ref; int irq; + bool disabled; struct list_head socket_mappings; spinlock_t socket_lock; @@ -131,6 +132,20 @@ static inline int get_request(struct pvcalls_bedata *bedata, int *req_id) return 0; } +/* + * Wait for the backend's response to req_id, or for the frontend to be + * disabled because the backend violated the wire protocol. Returns 0 once + * the response has arrived, or -EIO if the frontend was disabled. + */ +static int pvcalls_front_wait_rsp(struct pvcalls_bedata *bedata, u32 req_id) +{ + wait_event(bedata->inflight_req, + READ_ONCE(bedata->rsp[req_id].req_id) == req_id || + READ_ONCE(bedata->disabled)); + + return READ_ONCE(bedata->disabled) ? -EIO : 0; +} + static bool pvcalls_front_write_todo(struct sock_mapping *map) { struct pvcalls_data_intf *intf = map->active.ring; @@ -168,7 +183,8 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id) struct pvcalls_bedata *bedata; struct xen_pvcalls_response *rsp; uint8_t *src, *dst; - int req_id = 0, more = 0, done = 0; + u32 req_id = 0; + int more = 0, done = 0; if (dev == NULL) return IRQ_HANDLED; @@ -179,12 +195,31 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id) pvcalls_exit(); return IRQ_HANDLED; } + if (READ_ONCE(bedata->disabled)) { + pvcalls_exit(); + return IRQ_HANDLED; + } again: while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) { rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons); req_id = rsp->req_id; + if (req_id >= PVCALLS_NR_RSP_PER_RING) { + /* + * The backend supplied a req_id that would index + * bedata->rsp[] out of bounds: a protocol violation + * from a malicious or buggy backend. Log once, stop + * trusting this backend and disable the frontend rather + * than silently dropping the response and continuing. + */ + pr_err_once("pvcalls: backend sent out-of-range req_id %u, disabling frontend\n", + req_id); + WRITE_ONCE(bedata->disabled, true); + bedata->ring.rsp_cons++; + done = 1; + break; + } if (rsp->cmd == PVCALLS_POLL) { struct sock_mapping *map = (struct sock_mapping *)(uintptr_t) rsp->u.poll.id; @@ -217,7 +252,7 @@ static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id) } RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more); - if (more) + if (more && !READ_ONCE(bedata->disabled)) goto again; if (done) wake_up(&bedata->inflight_req); @@ -330,8 +365,11 @@ int pvcalls_front_socket(struct socket *sock) if (notify) notify_remote_via_irq(bedata->irq); - wait_event(bedata->inflight_req, - READ_ONCE(bedata->rsp[req_id].req_id) == req_id); + ret = pvcalls_front_wait_rsp(bedata, req_id); + if (ret) { + pvcalls_exit(); + return ret; + } /* read req_id, then the content */ smp_rmb(); @@ -477,8 +515,11 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, if (notify) notify_remote_via_irq(bedata->irq); - wait_event(bedata->inflight_req, - READ_ONCE(bedata->rsp[req_id].req_id) == req_id); + ret = pvcalls_front_wait_rsp(bedata, req_id); + if (ret) { + pvcalls_exit_sock(sock); + return ret; + } /* read req_id, then the content */ smp_rmb(); @@ -711,8 +752,11 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) if (notify) notify_remote_via_irq(bedata->irq); - wait_event(bedata->inflight_req, - READ_ONCE(bedata->rsp[req_id].req_id) == req_id); + ret = pvcalls_front_wait_rsp(bedata, req_id); + if (ret) { + pvcalls_exit_sock(sock); + return ret; + } /* read req_id, then the content */ smp_rmb(); @@ -761,8 +805,11 @@ int pvcalls_front_listen(struct socket *sock, int backlog) if (notify) notify_remote_via_irq(bedata->irq); - wait_event(bedata->inflight_req, - READ_ONCE(bedata->rsp[req_id].req_id) == req_id); + ret = pvcalls_front_wait_rsp(bedata, req_id); + if (ret) { + pvcalls_exit_sock(sock); + return ret; + } /* read req_id, then the content */ smp_rmb(); @@ -820,6 +867,14 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, } } + if (READ_ONCE(bedata->disabled)) { + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + wake_up(&map->passive.inflight_accept_req); + pvcalls_exit_sock(sock); + return -EIO; + } + map2 = kzalloc_obj(*map2); if (map2 == NULL) { clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, @@ -880,10 +935,18 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, } if (wait_event_interruptible(bedata->inflight_req, - READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) { + READ_ONCE(bedata->rsp[req_id].req_id) == req_id || + READ_ONCE(bedata->disabled))) { pvcalls_exit_sock(sock); return -EINTR; } + if (READ_ONCE(bedata->disabled)) { + clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, + (void *)&map->passive.flags); + wake_up(&map->passive.inflight_accept_req); + pvcalls_exit_sock(sock); + return -EIO; + } /* read req_id, then the content */ smp_rmb(); @@ -1054,7 +1117,8 @@ int pvcalls_front_release(struct socket *sock) notify_remote_via_irq(bedata->irq); wait_event(bedata->inflight_req, - READ_ONCE(bedata->rsp[req_id].req_id) == req_id); + READ_ONCE(bedata->rsp[req_id].req_id) == req_id || + READ_ONCE(bedata->disabled)); if (map->active_socket) { /* diff --git a/drivers/xen/xen-front-pgdir-shbuf.c b/drivers/xen/xen-front-pgdir-shbuf.c index 9c7d8af6e6a1..428187edf85d 100644 --- a/drivers/xen/xen-front-pgdir-shbuf.c +++ b/drivers/xen/xen-front-pgdir-shbuf.c @@ -445,8 +445,10 @@ static int grant_references(struct xen_front_pgdir_shbuf *buf) unsigned long frame; cur_ref = gnttab_claim_grant_reference(&priv_gref_head); - if (cur_ref < 0) - return cur_ref; + if (cur_ref < 0) { + ret = cur_ref; + goto out_free_refs; + } frame = xen_page_to_gfn(virt_to_page(buf->directory + PAGE_SIZE * i)); @@ -457,11 +459,13 @@ static int grant_references(struct xen_front_pgdir_shbuf *buf) if (buf->ops->grant_refs_for_buffer) { ret = buf->ops->grant_refs_for_buffer(buf, &priv_gref_head, j); if (ret) - return ret; + goto out_free_refs; } + ret = 0; +out_free_refs: gnttab_free_grant_references(priv_gref_head); - return 0; + return ret; } /* diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index c202e7c553a6..d1cca4acb6f3 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -417,6 +417,12 @@ static char **split_strings(char *strings, unsigned int len, unsigned int *num) { char *p, **ret; + if (len && strings[len - 1]) { + pr_err_once("malformed XS_DIRECTORY reply\n"); + kfree(strings); + return ERR_PTR(-EIO); + } + /* Count the strings. */ *num = count_strings(strings, len); diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 894d2bad6b6c..61354003c006 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -113,16 +113,12 @@ static struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell, { struct afs_volume *volume = NULL; struct rb_node *p; - int seq = 1; - for (;;) { + scoped_seqlock_read(&cell->volume_lock, ss_lock) { /* Unfortunately, rbtree walking doesn't give reliable results * under just the RCU read lock, so we have to check for * changes. */ - seq++; /* 2 on the 1st/lockless path, otherwise odd */ - read_seqbegin_or_lock(&cell->volume_lock, &seq); - p = rcu_dereference_raw(cell->volumes.rb_node); while (p) { volume = rb_entry(p, struct afs_volume, cell_node); @@ -138,12 +134,9 @@ static struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell, if (volume && afs_try_get_volume(volume, afs_volume_trace_get_callback)) break; - if (!need_seqretry(&cell->volume_lock, seq)) - break; - seq |= 1; /* Want a lock next time */ + volume = NULL; } - done_seqretry(&cell->volume_lock, seq); return volume; } @@ -221,7 +214,11 @@ static void afs_break_some_callbacks(struct afs_server *server, rcu_read_lock(); volume = afs_lookup_volume_rcu(server->cell, vid); - if (cbb->fid.vnode == 0 && cbb->fid.unique == 0) { + if (!volume) { + /* Ignore breaks on unknown volumes. */ + rcu_read_unlock(); + *_count = 0; + } else if (cbb->fid.vnode == 0 && cbb->fid.unique == 0) { afs_break_volume_callback(server, volume); *_count -= 1; if (*_count) diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 9738684dbdd2..47a2645768d7 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c @@ -206,11 +206,6 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, cell->dns_status = vllist->status; smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */ atomic_inc(&net->cells_outstanding); - ret = idr_alloc_cyclic(&net->cells_dyn_ino, cell, - 2, INT_MAX / 2, GFP_KERNEL); - if (ret < 0) - goto error; - cell->dynroot_ino = ret; cell->debug_id = atomic_inc_return(&cell_debug_id); trace_afs_cell(cell->debug_id, 1, 0, afs_cell_trace_alloc); @@ -304,6 +299,13 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, goto cell_already_exists; } + ret = idr_alloc_cyclic(&net->cells_dyn_ino, candidate, + 2, INT_MAX / 2, GFP_KERNEL); + if (ret < 0) + goto cant_alloc_ino; + candidate->dynroot_ino = ret; + set_bit(AFS_CELL_FL_HAVE_INO, &candidate->flags); + cell = candidate; candidate = NULL; afs_use_cell(cell, trace); @@ -378,6 +380,11 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, _leave(" = %p [cell]", cell); return cell; +cant_alloc_ino: + up_write(&net->cells_lock); + afs_put_cell(candidate, afs_cell_trace_put_candidate); + goto error_noput; + cell_already_exists: _debug("cell exists"); cell = cursor; @@ -547,6 +554,8 @@ static int afs_update_cell(struct afs_cell *cell) rcu_assign_pointer(cell->vl_servers, vllist); cell->dns_source = vllist->source; old = p; + } else { + old = vllist; } write_unlock(&cell->vl_servers_lock); afs_put_vlserverlist(cell->net, old); @@ -577,7 +586,6 @@ static void afs_cell_destroy(struct rcu_head *rcu) afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers)); afs_unuse_cell(cell->alias_of, afs_cell_trace_unuse_alias); key_put(cell->anonymous_key); - idr_remove(&net->cells_dyn_ino, cell->dynroot_ino); kfree(cell->name - 1); kfree(cell); @@ -592,6 +600,13 @@ static void afs_destroy_cell_work(struct work_struct *work) afs_see_cell(cell, afs_cell_trace_destroy); timer_delete_sync(&cell->management_timer); cancel_work_sync(&cell->manager); + + if (test_bit(AFS_CELL_FL_HAVE_INO, &cell->flags)) { + down_write(&cell->net->cells_lock); + idr_remove(&cell->net->cells_dyn_ino, cell->dynroot_ino); + up_write(&cell->net->cells_lock); + } + call_rcu(&cell->rcu, afs_cell_destroy); } diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index 5540ae1cad59..db394f101fc6 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -334,7 +334,6 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) ret = afs_extract_data(call, false); switch (ret) { case 0: break; - case -EAGAIN: return 0; default: return ret; } @@ -364,6 +363,11 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) return afs_io_error(call, afs_io_error_cm_reply); + if (!call->server) { + trace_afs_cm_no_server_u(call, call->request); + return 0; + } + if (memcmp(call->request, &call->server->_uuid, sizeof(call->server->_uuid)) != 0) { pr_notice("Callback UUID does not match fileserver UUID\n"); trace_afs_cm_no_server_u(call, call->request); @@ -451,7 +455,6 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) ret = afs_extract_data(call, false); switch (ret) { case 0: break; - case -EAGAIN: return 0; default: return ret; } diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 498b99ccdf0e..6df56fe9163f 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -28,9 +28,11 @@ static int afs_d_revalidate(struct inode *dir, const struct qstr *name, static int afs_d_delete(const struct dentry *dentry); static void afs_d_iput(struct dentry *dentry, struct inode *inode); static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, - loff_t fpos, u64 ino, unsigned dtype); + u64 ino, u32 uniquifier); +#define AFS_LOOKUP_ONE ((filldir_t)0x123UL) static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, - loff_t fpos, u64 ino, unsigned dtype); + u64 ino, u32 uniquifier); +#define AFS_LOOKUP ((filldir_t)0x137UL) static int afs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl); static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, @@ -421,11 +423,18 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode, } /* found the next entry */ - if (!dir_emit(ctx, dire->u.name, nlen, - ntohl(dire->u.vnode), - (ctx->actor == afs_lookup_filldir || - ctx->actor == afs_lookup_one_filldir)? - ntohl(dire->u.unique) : DT_UNKNOWN)) { + if (ctx->actor == AFS_LOOKUP) { + if (!afs_lookup_filldir(ctx, dire->u.name, nlen, + ntohl(dire->u.vnode), + ntohl(dire->u.unique))) + return 0; + } else if (ctx->actor == AFS_LOOKUP_ONE) { + if (!afs_lookup_one_filldir(ctx, dire->u.name, nlen, + ntohl(dire->u.vnode), + ntohl(dire->u.unique))) + return 0; + } else if (!dir_emit(ctx, dire->u.name, nlen, + ntohl(dire->u.vnode), DT_UNKNOWN)) { _leave(" = 0 [full]"); return 0; } @@ -545,6 +554,7 @@ static int afs_readdir(struct file *file, struct dir_context *ctx) { afs_dataversion_t dir_version; + ctx->dt_flags_mask = UINT_MAX; return afs_dir_iterate(file_inode(file), ctx, file, &dir_version); } @@ -554,14 +564,14 @@ static int afs_readdir(struct file *file, struct dir_context *ctx) * uniquifier through dtype */ static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, - int nlen, loff_t fpos, u64 ino, unsigned dtype) + int nlen, u64 ino, u32 uniquifier) { struct afs_lookup_one_cookie *cookie = container_of(ctx, struct afs_lookup_one_cookie, ctx); _enter("{%s,%u},%s,%u,,%llu,%u", cookie->name.name, cookie->name.len, name, nlen, - (unsigned long long) ino, dtype); + (unsigned long long) ino, uniquifier); /* insanity checks first */ BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); @@ -574,7 +584,7 @@ static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, } cookie->fid.vnode = ino; - cookie->fid.unique = dtype; + cookie->fid.unique = uniquifier; cookie->found = 1; _leave(" = false [found]"); @@ -591,7 +601,7 @@ static int afs_do_lookup_one(struct inode *dir, const struct qstr *name, { struct afs_super_info *as = dir->i_sb->s_fs_info; struct afs_lookup_one_cookie cookie = { - .ctx.actor = afs_lookup_one_filldir, + .ctx.actor = AFS_LOOKUP_ONE, .name = *name, .fid.vid = as->volume->vid }; @@ -622,14 +632,14 @@ static int afs_do_lookup_one(struct inode *dir, const struct qstr *name, * uniquifier through dtype */ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, - int nlen, loff_t fpos, u64 ino, unsigned dtype) + int nlen, u64 ino, u32 uniquifier) { struct afs_lookup_cookie *cookie = container_of(ctx, struct afs_lookup_cookie, ctx); _enter("{%s,%u},%s,%u,,%llu,%u", cookie->name.name, cookie->name.len, name, nlen, - (unsigned long long) ino, dtype); + (unsigned long long) ino, uniquifier); /* insanity checks first */ BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); @@ -637,7 +647,7 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, if (cookie->nr_fids < 50) { cookie->fids[cookie->nr_fids].vnode = ino; - cookie->fids[cookie->nr_fids].unique = dtype; + cookie->fids[cookie->nr_fids].unique = uniquifier; cookie->nr_fids++; } @@ -778,7 +788,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry) for (i = 0; i < ARRAY_SIZE(cookie->fids); i++) cookie->fids[i].vid = dvnode->fid.vid; - cookie->ctx.actor = afs_lookup_filldir; + cookie->ctx.actor = AFS_LOOKUP; cookie->name = dentry->d_name; cookie->nr_fids = 2; /* slot 1 is saved for the fid we actually want * and slot 0 for the directory */ diff --git a/fs/afs/dynroot.c b/fs/afs/dynroot.c index 1d5e33bc7502..6e3c8c691ba9 100644 --- a/fs/afs/dynroot.c +++ b/fs/afs/dynroot.c @@ -278,7 +278,7 @@ static struct dentry *afs_lookup_atcell(struct inode *dir, struct dentry *dentry } /* - * Transcribe the cell database into readdir content under the RCU read lock. + * Transcribe the cell database into readdir content under net->cells_lock. * Each cell produces two entries, one prefixed with a dot and one not. */ static int afs_dynroot_readdir_cells(struct afs_net *net, struct dir_context *ctx) diff --git a/fs/afs/fs_operation.c b/fs/afs/fs_operation.c index c0dbbc6d3716..20801b29521d 100644 --- a/fs/afs/fs_operation.c +++ b/fs/afs/fs_operation.c @@ -348,7 +348,7 @@ int afs_put_operation(struct afs_operation *op) for (i = 0; i < op->nr_files - 2; i++) if (op->more_files[i].put_vnode) iput(&op->more_files[i].vnode->netfs.inode); - kfree(op->more_files); + kvfree(op->more_files); } if (op->estate) { diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 3f48458694ba..14f39a9bea6c 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -52,9 +52,9 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren /* * Set parameters for the netfs library */ -static void afs_set_netfs_context(struct afs_vnode *vnode) +static void afs_set_netfs_context(struct afs_vnode *vnode, bool is_file) { - netfs_inode_init(&vnode->netfs, &afs_req_ops, true); + netfs_inode_init(&vnode->netfs, &afs_req_ops, is_file); } /* @@ -93,6 +93,10 @@ static int afs_inode_init_from_status(struct afs_operation *op, inode->i_gid = make_kgid(&init_user_ns, status->group); set_nlink(&vnode->netfs.inode, status->nlink); + i_size_write(inode, status->size); + inode_set_bytes(inode, status->size); + afs_set_netfs_context(vnode, status->type == AFS_FTYPE_FILE); + switch (status->type) { case AFS_FTYPE_FILE: inode->i_mode = S_IFREG | (status->mode & S_IALLUGO); @@ -126,7 +130,6 @@ static int afs_inode_init_from_status(struct afs_operation *op, } inode->i_mapping->a_ops = &afs_symlink_aops; inode_nohighmem(inode); - mapping_set_release_always(inode->i_mapping); break; default: dump_vnode(vnode, op->file[0].vnode != vnode ? op->file[0].vnode : NULL); @@ -134,10 +137,6 @@ static int afs_inode_init_from_status(struct afs_operation *op, return afs_protocol_error(NULL, afs_eproto_file_type); } - i_size_write(inode, status->size); - inode_set_bytes(inode, status->size); - afs_set_netfs_context(vnode); - vnode->invalid_before = status->data_version; trace_afs_set_dv(vnode, status->data_version); inode_set_iversion_raw(&vnode->netfs.inode, status->data_version); @@ -566,7 +565,6 @@ struct inode *afs_root_iget(struct super_block *sb, struct key *key) vnode = AFS_FS_I(inode); vnode->cb_v_check = atomic_read(&as->volume->cb_v_break); - afs_set_netfs_context(vnode); op = afs_alloc_operation(key, as->volume); if (IS_ERR(op)) { @@ -682,6 +680,7 @@ void afs_evict_inode(struct inode *inode) inode->i_mapping->a_ops->writepages(inode->i_mapping, &wbc); } + flush_delayed_work(&vnode->lock_work); netfs_wait_for_outstanding_io(inode); truncate_inode_pages_final(&inode->i_data); netfs_free_folioq_buffer(vnode->directory); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 0b72a8566299..601f01e5c15f 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -388,6 +388,7 @@ struct afs_cell { #define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */ #define AFS_CELL_FL_DO_LOOKUP 1 /* DNS lookup requested */ #define AFS_CELL_FL_CHECK_ALIAS 2 /* Need to check for aliases */ +#define AFS_CELL_FL_HAVE_INO 3 /* Have dynroot_ino */ enum afs_cell_state state; short error; enum dns_record_source dns_source:8; /* Latest source of data from lookup */ @@ -750,8 +751,6 @@ static inline void afs_vnode_set_cache(struct afs_vnode *vnode, { #ifdef CONFIG_AFS_FSCACHE vnode->netfs.cache = cookie; - if (cookie) - mapping_set_release_always(vnode->netfs.inode.i_mapping); #endif } diff --git a/fs/afs/super.c b/fs/afs/super.c index 942f3e9800d7..82bb713825a0 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -587,7 +587,8 @@ static int afs_get_tree(struct fs_context *fc) } fc->root = dget(sb->s_root); - trace_afs_get_tree(as->cell, as->volume); + if (!ctx->dyn_root) + trace_afs_get_tree(as->cell, as->volume); _leave(" = 0 [%p]", sb); return 0; @@ -659,7 +660,6 @@ static void afs_i_init_once(void *_vnode) INIT_LIST_HEAD(&vnode->wb_keys); INIT_LIST_HEAD(&vnode->pending_locks); INIT_LIST_HEAD(&vnode->granted_locks); - INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); INIT_LIST_HEAD(&vnode->cb_mmap_link); seqlock_init(&vnode->cb_lock); } @@ -693,6 +693,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) init_rwsem(&vnode->rmdir_lock); INIT_WORK(&vnode->cb_work, afs_invalidate_mmap_work); + INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); _leave(" = %p", &vnode->netfs.inode); return &vnode->netfs.inode; diff --git a/fs/afs/symlink.c b/fs/afs/symlink.c index ed5868369f37..16b4823cb7b7 100644 --- a/fs/afs/symlink.c +++ b/fs/afs/symlink.c @@ -255,11 +255,11 @@ int afs_symlink_writepages(struct address_space *mapping, } if (ret == 0) { - mutex_lock(&vnode->netfs.wb_lock); + netfs_wb_begin(&vnode->netfs, false); netfs_free_folioq_buffer(vnode->directory); vnode->directory = NULL; vnode->directory_size = 0; - mutex_unlock(&vnode->netfs.wb_lock); + netfs_wb_end(&vnode->netfs); } else if (ret == 1) { ret = 0; /* Skipped write due to lock conflict. */ } diff --git a/fs/afs/vl_list.c b/fs/afs/vl_list.c index 3e4966915ea4..c1dac5dbed0d 100644 --- a/fs/afs/vl_list.c +++ b/fs/afs/vl_list.c @@ -92,7 +92,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, { struct afs_addr_list *alist; const u8 *b = *_b; - int ret = -EINVAL; + int ret; alist = afs_alloc_addrlist(nr_addrs); if (!alist) @@ -110,6 +110,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, case DNS_ADDRESS_IS_IPV4: if (end - b < 4) { _leave(" = -EINVAL [short inet]"); + ret = -EINVAL; goto error; } memcpy(x, b, 4); @@ -122,6 +123,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, case DNS_ADDRESS_IS_IPV6: if (end - b < 16) { _leave(" = -EINVAL [short inet6]"); + ret = -EINVAL; goto error; } memcpy(x, b, 16); @@ -198,6 +200,8 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, b += sizeof(*hdr); while (end - b >= sizeof(bs)) { + int nlen; + bs.name_len = afs_extract_le16(&b); bs.priority = afs_extract_le16(&b); bs.weight = afs_extract_le16(&b); @@ -207,10 +211,12 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, bs.protocol = *b++; bs.nr_addrs = *b++; + nlen = min3(bs.name_len, end - b, 255); + _debug("extract %u %u %u %u %u %u %*.*s", bs.name_len, bs.priority, bs.weight, bs.port, bs.protocol, bs.nr_addrs, - bs.name_len, bs.name_len, b); + bs.name_len, nlen, b); if (end - b < bs.name_len) break; @@ -287,8 +293,20 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, afs_put_addrlist(old, afs_alist_trace_put_vlserver_old); } + /* Check for duplicates in the server list */ + for (j = 0; j < vllist->nr_servers; j++) { + struct afs_vlserver *s = vllist->servers[j].server; - /* TODO: Might want to check for duplicates */ + if (s->name_len == server->name_len && + s->port == server->port && + strncasecmp(s->name, server->name, server->name_len) == 0) { + afs_put_vlserver(cell->net, server); + server = NULL; + break; + } + } + if (!server) + continue; /* Insertion-sort by priority and weight */ for (j = 0; j < vllist->nr_servers; j++) { diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 9ae5c8ad2e04..4f79d25ec37f 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c @@ -40,7 +40,7 @@ static struct afs_volume *afs_insert_volume_into_cell(struct afs_cell *cell, goto found; } - set_bit(AFS_VOLUME_RM_TREE, &volume->flags); + set_bit(AFS_VOLUME_RM_TREE, &p->flags); rb_replace_node_rcu(&p->cell_node, &volume->cell_node, &cell->volumes); } } diff --git a/fs/bpf_fs_kfuncs.c b/fs/bpf_fs_kfuncs.c index 768aca2dc0f0..f1863a891db6 100644 --- a/fs/bpf_fs_kfuncs.c +++ b/fs/bpf_fs_kfuncs.c @@ -360,18 +360,23 @@ __bpf_kfunc int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__s #endif /* CONFIG_CGROUPS */ /** - * bpf_real_inode - get the real inode backing a dentry - * @dentry: dentry to resolve + * bpf_real_data_inode - get the real inode hosting a file's data + * @file: file to resolve * - * If the dentry is on a union/overlay filesystem, return the underlying, real - * inode that hosts the data. Otherwise return the inode attached to the - * dentry itself. + * Resolve @file to the inode that hosts its data. For a regular file on a + * union/overlay filesystem this is the underlying (upper or lower) inode that + * stores the data, not the overlay inode. * - * Return: The real inode backing the dentry, or NULL for a negative dentry. + * Data resolution only applies to regular files. For a non-regular file (e.g. + * a device node, fifo or socket) on a union/overlay filesystem the overlay + * inode itself is returned; for any file on a non-union filesystem the inode + * attached to @file is returned. + * + * Return: The inode hosting @file's data, or NULL. */ -__bpf_kfunc struct inode *bpf_real_inode(struct dentry *dentry) +__bpf_kfunc struct inode *bpf_real_data_inode(struct file *file) { - return d_real_inode(dentry); + return d_real_inode(file_dentry(file)); } __bpf_kfunc_end_defs(); @@ -384,7 +389,7 @@ BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE) BTF_ID_FLAGS(func, bpf_remove_dentry_xattr, KF_SLEEPABLE) -BTF_ID_FLAGS(func, bpf_real_inode, KF_SLEEPABLE | KF_RET_NULL) +BTF_ID_FLAGS(func, bpf_real_data_inode, KF_SLEEPABLE | KF_RET_NULL) BTF_KFUNCS_END(bpf_fs_kfunc_set_ids) static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id) diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index 2937db690b40..8a9f6be15828 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -209,7 +209,6 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache, return ERR_PTR(ret); nomem_d_alloc: - inode_unlock(d_inode(dir)); _leave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); } @@ -375,7 +374,7 @@ int cachefiles_bury_object(struct cachefiles_cache *cache, "Rename failed with error %d", ret); } - __cachefiles_unmark_inode_in_use(object, d_inode(rep)); + cachefiles_do_unmark_inode_in_use(object, d_inode(rep)); end_renaming(&rd); _leave(" = 0"); return 0; @@ -467,7 +466,6 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object) ret = -EINVAL; if (unlikely(!file->f_op->read_iter) || unlikely(!file->f_op->write_iter)) { - fput(file); pr_notice("Cache does not support read_iter and write_iter\n"); goto err_unuse; } diff --git a/fs/exec.c b/fs/exec.c index b92fe7db176c..d5993cedc829 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -1717,7 +1717,7 @@ static int exec_binprm(struct linux_binprm *bprm) old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent)); rcu_read_unlock(); - /* This allows 4 levels of binfmt rewrites before failing hard. */ + /* This allows 5 levels of binfmt rewrites before failing hard. */ for (depth = 0;; depth++) { struct file *exec; if (depth > 5) diff --git a/fs/exfat/iomap.c b/fs/exfat/iomap.c index 1aac38e63fe6..190fc6471f84 100644 --- a/fs/exfat/iomap.c +++ b/fs/exfat/iomap.c @@ -253,10 +253,7 @@ static void exfat_iomap_read_end_io(struct bio *bio) static void exfat_iomap_bio_submit_read(const struct iomap_iter *iter, struct iomap_read_folio_ctx *ctx) { - struct bio *bio = ctx->read_ctx; - - bio->bi_end_io = exfat_iomap_read_end_io; - submit_bio(bio); + iomap_bio_submit_read_endio(iter, ctx, exfat_iomap_read_end_io); } const struct iomap_read_ops exfat_iomap_bio_read_ops = { diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 4f6f42f33613..c6cca5d00ffd 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -130,6 +130,31 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, return fat__get_entry(dir, pos, bh, de); } +/* + * Like fat_get_entry(), but honour the FAT end-of-directory marker: + * a dirent whose first name byte is NUL terminates iteration per the + * spec, which also guarantees that every following slot is zeroed. + * Skip straight to the end of the directory so the next call returns + * -1 from fat_bmap() without re-reading the trailing zero slots, and + * so callers that persist *pos across invocations (e.g. readdir's + * ctx->pos) keep reporting EOD. Release *bh and set it to NULL to + * match fat_get_entry()'s contract that *bh is NULL on the -1 return. + */ +static int fat_get_entry_eod(struct inode *dir, loff_t *pos, + struct buffer_head **bh, + struct msdos_dir_entry **de) +{ + int err = fat_get_entry(dir, pos, bh, de); + + if (err == 0 && (*de)->name[0] == 0) { + brelse(*bh); + *bh = NULL; + *pos = dir->i_size; + return -1; + } + return err; +} + /* * Convert Unicode 16 to UTF-8, translated Unicode, or ASCII. * If uni_xlate is enabled and we can't get a 1:1 conversion, use a @@ -327,7 +352,7 @@ static int fat_parse_long(struct inode *dir, loff_t *pos, if (ds->id & 0x40) (*unicode)[offset + 13] = 0; - if (fat_get_entry(dir, pos, bh, de) < 0) + if (fat_get_entry_eod(dir, pos, bh, de) < 0) return PARSE_EOF; if (slot == 0) break; @@ -489,7 +514,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name, err = -ENOENT; while (1) { - if (fat_get_entry(inode, &cpos, &bh, &de) == -1) + if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1) goto end_of_dir; parse_record: nr_slots = 0; @@ -601,7 +626,7 @@ static int __fat_readdir(struct inode *inode, struct file *file, bh = NULL; get_new: - if (fat_get_entry(inode, &cpos, &bh, &de) == -1) + if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1) goto end_of_dir; parse_record: nr_slots = 0; @@ -885,7 +910,7 @@ static int fat_get_short_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh, struct msdos_dir_entry **de) { - while (fat_get_entry(dir, pos, bh, de) >= 0) { + while (fat_get_entry_eod(dir, pos, bh, de) >= 0) { /* free entry or long name entry or volume label */ if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME)) return 0; @@ -1302,6 +1327,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, struct msdos_dir_entry *de; int err, free_slots, i, nr_bhs; loff_t pos; + bool saw_eod; sinfo->nr_slots = nr_slots; @@ -1310,12 +1336,15 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, bh = prev = NULL; pos = 0; err = -ENOSPC; + saw_eod = false; while (fat_get_entry(dir, &pos, &bh, &de) > -1) { /* check the maximum size of directory */ if (pos >= FAT_MAX_DIR_SIZE) goto error; if (IS_FREE(de->name)) { + if (de->name[0] == 0) + saw_eod = true; if (prev != bh) { get_bh(bh); bhs[nr_bhs] = prev = bh; @@ -1325,6 +1354,13 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, if (free_slots == nr_slots) goto found; } else { + if (saw_eod) { + fat_fs_error_ratelimit(sb, + "allocated dir entry found after end-of-directory marker (i_pos %lld)", + MSDOS_I(dir)->i_pos); + err = -EIO; + goto error; + } for (i = 0; i < nr_bhs; i++) brelse(bhs[i]); prev = NULL; diff --git a/fs/fhandle.c b/fs/fhandle.c index 1ca7eb3a6cb5..f8829231e3d7 100644 --- a/fs/fhandle.c +++ b/fs/fhandle.c @@ -295,7 +295,7 @@ static bool capable_wrt_mount(struct mount *mount) */ guard(rcu)(); mnt_ns = READ_ONCE(mount->mnt_ns); - return ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN); + return mnt_ns && ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN); } static inline int may_decode_fh(struct handle_to_path_ctx *ctx, diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c index e85222892038..1b8216eb1d90 100644 --- a/fs/freevxfs/vxfs_bmap.c +++ b/fs/freevxfs/vxfs_bmap.c @@ -227,7 +227,8 @@ vxfs_bmap_typed(struct inode *ip, long iblock) return 0; } default: - BUG(); + WARN_ON_ONCE(1); + return 0; } } diff --git a/fs/fuse/file.c b/fs/fuse/file.c index e052a0d44dee..ceada75310b8 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -981,19 +981,8 @@ static int fuse_iomap_read_folio_range_async(const struct iomap_iter *iter, return ret; } -static void fuse_iomap_submit_read(const struct iomap_iter *iter, - struct iomap_read_folio_ctx *ctx) -{ - struct fuse_fill_read_data *data = ctx->read_ctx; - - if (data->ia) - fuse_send_readpages(data->ia, data->file, data->nr_bytes, - data->fc->async_read); -} - static const struct iomap_read_ops fuse_iomap_read_ops = { .read_folio_range = fuse_iomap_read_folio_range_async, - .submit_read = fuse_iomap_submit_read, }; static int fuse_read_folio(struct file *file, struct folio *folio) @@ -1116,6 +1105,9 @@ static void fuse_readahead(struct readahead_control *rac) return; iomap_readahead(&fuse_iomap_ops, &ctx, NULL); + if (data.ia) + fuse_send_readpages(data.ia, data.file, data.nr_bytes, + fc->async_read); } static ssize_t fuse_cache_read_iter(struct kiocb *iocb, struct iov_iter *to) diff --git a/fs/iomap/bio.c b/fs/iomap/bio.c index 4504f4633f17..dc8ac7e370a5 100644 --- a/fs/iomap/bio.c +++ b/fs/iomap/bio.c @@ -78,14 +78,24 @@ u32 iomap_finish_ioend_buffered_read(struct iomap_ioend *ioend) return __iomap_read_end_io(&ioend->io_bio, ioend->io_error); } -static void iomap_bio_submit_read(const struct iomap_iter *iter, - struct iomap_read_folio_ctx *ctx) +void iomap_bio_submit_read_endio(const struct iomap_iter *iter, + struct iomap_read_folio_ctx *ctx, bio_end_io_t end_io) { struct bio *bio = ctx->read_ctx; + bio->bi_end_io = end_io; if (iter->iomap.flags & IOMAP_F_INTEGRITY) fs_bio_integrity_alloc(bio); submit_bio(bio); + + ctx->read_ctx = NULL; +} +EXPORT_SYMBOL_GPL(iomap_bio_submit_read_endio); + +static void iomap_bio_submit_read(const struct iomap_iter *iter, + struct iomap_read_folio_ctx *ctx) +{ + return iomap_bio_submit_read_endio(iter, ctx, iomap_read_end_io); } static struct bio_set *iomap_read_bio_set(struct iomap_read_folio_ctx *ctx) @@ -127,7 +137,6 @@ static void iomap_read_alloc_bio(const struct iomap_iter *iter, if (ctx->rac) bio->bi_opf |= REQ_RAHEAD; bio->bi_iter.bi_sector = iomap_sector(iomap, iter->pos); - bio->bi_end_io = iomap_read_end_io; bio_add_folio_nofail(bio, folio, plen, offset_in_folio(folio, iter->pos)); ctx->read_ctx = bio; diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 8d4806dc46d4..276720bc18dc 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -642,12 +642,12 @@ void iomap_read_folio(const struct iomap_ops *ops, fsverity_readahead(ctx->vi, folio->index, folio_nr_pages(folio)); - while ((ret = iomap_iter(&iter, ops)) > 0) + while ((ret = iomap_iter(&iter, ops)) > 0) { iter.status = iomap_read_folio_iter(&iter, ctx, &bytes_submitted); - - if (ctx->read_ctx && ctx->ops->submit_read) - ctx->ops->submit_read(&iter, ctx); + if (ctx->read_ctx && ctx->ops->submit_read) + ctx->ops->submit_read(&iter, ctx); + } if (ctx->cur_folio) iomap_read_end(ctx->cur_folio, bytes_submitted); @@ -718,12 +718,12 @@ void iomap_readahead(const struct iomap_ops *ops, fsverity_readahead(ctx->vi, readahead_index(rac), readahead_count(rac)); - while (iomap_iter(&iter, ops) > 0) + while (iomap_iter(&iter, ops) > 0) { iter.status = iomap_readahead_iter(&iter, ctx, &cur_bytes_submitted); - - if (ctx->read_ctx && ctx->ops->submit_read) - ctx->ops->submit_read(&iter, ctx); + if (ctx->read_ctx && ctx->ops->submit_read) + ctx->ops->submit_read(&iter, ctx); + } if (ctx->cur_folio) iomap_read_end(ctx->cur_folio, cur_bytes_submitted); diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c index b485e3b191da..e2cd5f92babe 100644 --- a/fs/iomap/direct-io.c +++ b/fs/iomap/direct-io.c @@ -369,7 +369,7 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter, */ if ((op & REQ_ATOMIC) && WARN_ON_ONCE(ret != iomap_length(iter))) { ret = -EINVAL; - goto out_put_bio; + goto out_bio_release_pages; } if (iter->iomap.flags & IOMAP_F_INTEGRITY) { @@ -393,6 +393,11 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter, iomap_dio_submit_bio(iter, dio, bio, pos); return ret; +out_bio_release_pages: + if (dio->flags & IOMAP_DIO_BOUNCE) + bio_iov_iter_unbounce(bio, true, false); + else + bio_release_pages(bio, false); out_put_bio: bio_put(bio); return ret; diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c index f7c3e0c70fd7..0565328764c1 100644 --- a/fs/iomap/ioend.c +++ b/fs/iomap/ioend.c @@ -298,8 +298,12 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio, * appending writes. */ ioend->io_size += map_len; - if (ioend->io_offset + ioend->io_size > end_pos) - ioend->io_size = end_pos - ioend->io_offset; + if (ioend->io_offset + ioend->io_size > end_pos) { + if (ioend->io_offset >= end_pos) + ioend->io_size = 0; + else + ioend->io_size = end_pos - ioend->io_offset; + } wbc_account_cgroup_owner(wpc->wbc, folio, map_len); return map_len; diff --git a/fs/minix/minix.h b/fs/minix/minix.h index f2025c9b5825..9e52d4302f0d 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h @@ -97,7 +97,7 @@ static inline struct minix_inode_info *minix_i(struct inode *inode) static inline unsigned minix_blocks_needed(unsigned bits, unsigned blocksize) { - return DIV_ROUND_UP(bits, blocksize * 8); + return DIV_ROUND_UP_POW2(bits, blocksize * 8); } #if defined(CONFIG_MINIX_FS_NATIVE_ENDIAN) && \ diff --git a/fs/namei.c b/fs/namei.c index 5cc9f0f466b8..19ce43c9a6e6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4736,6 +4736,10 @@ int vfs_tmpfile(struct mnt_idmap *idmap, int error; int open_flag = file->f_flags; + /* A tmpfile is I_LINKABLE, so guard its owner like may_o_create(). */ + if (!fsuidgid_has_mapping(dir->i_sb, idmap)) + return -EOVERFLOW; + /* we want directory to be writable */ error = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC); if (error) diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c index 76d0f6a29aba..24a8a5418e31 100644 --- a/fs/netfs/buffered_read.c +++ b/fs/netfs/buffered_read.c @@ -659,7 +659,7 @@ int netfs_write_begin(struct netfs_inode *ctx, * within the cache granule containing the EOF, in which case we need * to preload the granule. */ - if (!netfs_is_cache_enabled(ctx) && + if (!netfs_is_cache_maybe_enabled(ctx) && netfs_skip_folio_read(folio, pos, len, false)) { netfs_stat(&netfs_n_rh_write_zskip); goto have_folio_no_wait; diff --git a/fs/netfs/buffered_write.c b/fs/netfs/buffered_write.c index 6bde3320bcec..2cdb68e6b16f 100644 --- a/fs/netfs/buffered_write.c +++ b/fs/netfs/buffered_write.c @@ -277,7 +277,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, * caching service temporarily because the backing store got * culled. */ - if (netfs_is_cache_enabled(ctx)) { + if (netfs_is_cache_maybe_enabled(ctx)) { if (finfo) { netfs_stat(&netfs_n_wh_wstream_conflict); goto flush_content; diff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c index 25f8ceb15fad..c16fbad286a1 100644 --- a/fs/netfs/direct_write.c +++ b/fs/netfs/direct_write.c @@ -166,13 +166,16 @@ static int netfs_unbuffered_write(struct netfs_io_request *wreq) */ subreq->error = -EAGAIN; trace_netfs_sreq(subreq, netfs_sreq_trace_retry); - if (subreq->transferred > 0) + if (subreq->transferred > 0) { iov_iter_advance(&wreq->buffer.iter, subreq->transferred); + wreq->transferred += subreq->transferred; + } if (stream->source == NETFS_UPLOAD_TO_SERVER && wreq->netfs_ops->retry_request) wreq->netfs_ops->retry_request(wreq, stream); + __clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); __clear_bit(NETFS_SREQ_BOUNDARY, &subreq->flags); __clear_bit(NETFS_SREQ_FAILED, &subreq->flags); @@ -186,17 +189,10 @@ static int netfs_unbuffered_write(struct netfs_io_request *wreq) netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit); - if (stream->prepare_write) { + if (stream->prepare_write) stream->prepare_write(subreq); - __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); - netfs_stat(&netfs_n_wh_retry_write_subreq); - } else { - struct iov_iter source; - - netfs_reset_iter(subreq); - source = subreq->io_iter; - netfs_reissue_write(stream, subreq, &source); - } + __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); + netfs_stat(&netfs_n_wh_retry_write_subreq); } netfs_unbuffered_write_done(wreq); diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h index 645996ecfc80..d889caa401dc 100644 --- a/fs/netfs/internal.h +++ b/fs/netfs/internal.h @@ -239,6 +239,18 @@ static inline bool netfs_is_cache_enabled(struct netfs_inode *ctx) #endif } +static inline bool netfs_is_cache_maybe_enabled(struct netfs_inode *ctx) +{ +#if IS_ENABLED(CONFIG_FSCACHE) + struct fscache_cookie *cookie = ctx->cache; + + return fscache_cookie_valid(cookie) && + test_bit(FSCACHE_COOKIE_IS_CACHING, &cookie->flags); +#else + return false; +#endif +} + /* * Get a ref on a netfs group attached to a dirty page (e.g. a ceph snap). */ diff --git a/fs/netfs/locking.c b/fs/netfs/locking.c index 2249ecd09d0a..4e3be2b81504 100644 --- a/fs/netfs/locking.c +++ b/fs/netfs/locking.c @@ -9,6 +9,11 @@ #include #include "internal.h" +struct netfs_wb_waiter { + struct list_head link; /* Link in ictx->wb_queue */ + struct task_struct *waiter; /* Waiter task; cleared when lock granted */ +}; + /* * inode_dio_wait_interruptible - wait for outstanding DIO requests to finish * @inode: inode to wait for @@ -203,3 +208,93 @@ void netfs_end_io_direct(struct inode *inode) up_read(&inode->i_rwsem); } EXPORT_SYMBOL(netfs_end_io_direct); + +/* + * Wait to have exclusive access to writeback. + */ +static bool netfs_wb_begin_wait(struct netfs_inode *ictx) +{ + struct netfs_wb_waiter waiter = {}; + struct task_struct *tsk = current; + bool got = false; + + spin_lock(&ictx->lock); + + if (test_and_set_bit_lock(NETFS_ICTX_WB_LOCK, &ictx->flags)) { + get_task_struct(tsk); + waiter.waiter = tsk; + list_add_tail(&waiter.link, &ictx->wb_queue); + } else { + got = true; + } + spin_unlock(&ictx->lock); + + if (!got) { + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + /* Read waiter before accessing inode state. */ + if (smp_load_acquire(&waiter.waiter) == NULL) + break; + schedule(); + } + } + __set_current_state(TASK_RUNNING); + return true; +} + +/** + * netfs_wb_begin - Begin writeback, waiting if need be + * @ictx: The inode to get writeback access on + * @nowait: Return failure immediately rather than waiting if true + * + * Begin writeback to an inode, waiting for exclusive access if @nowait is + * false. This prevents collection from being done out of order with respect + * to the issuance of write subrequests. + * + * Note that writeback may be ended in a different process (e.g. the collection + * function on a workqueue) than started it. + * + * Return: True if can proceed, false if denied. + */ +bool netfs_wb_begin(struct netfs_inode *ictx, bool nowait) +{ + if (!test_and_set_bit_lock(NETFS_ICTX_WB_LOCK, &ictx->flags)) + return true; + if (nowait) { + netfs_stat(&netfs_n_wb_lock_skip); + return false; + } + netfs_stat(&netfs_n_wb_lock_wait); + return netfs_wb_begin_wait(ictx); +} +EXPORT_SYMBOL(netfs_wb_begin); + +/* netfs_wb_end - End writeback + * @ictx: The inode we have writeback access to + * + * End writeback access on an inode, waking up the next writeback request. + */ +void netfs_wb_end(struct netfs_inode *ictx) +{ + struct netfs_wb_waiter *waiter; + struct task_struct *tsk; + + WARN_ON_ONCE(!test_bit(NETFS_ICTX_WB_LOCK, &ictx->flags)); + + spin_lock(&ictx->lock); + + waiter = list_first_entry_or_null(&ictx->wb_queue, struct netfs_wb_waiter, link); + if (waiter) { + list_del(&waiter->link); + tsk = waiter->waiter; + /* Write inode state before clearing waiter. */ + smp_store_release(&waiter->waiter, NULL); + wake_up_process(tsk); + put_task_struct(tsk); + } else { + clear_bit_unlock(NETFS_ICTX_WB_LOCK, &ictx->flags); + } + + spin_unlock(&ictx->lock); +} +EXPORT_SYMBOL(netfs_wb_end); diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c index f59a70f3a086..2b42758e01ec 100644 --- a/fs/netfs/read_retry.c +++ b/fs/netfs/read_retry.c @@ -98,7 +98,12 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) goto abandon; } - list_for_each_continue(next, &stream->subrequests) { + for (;;) { + /* Read pointer to subreq before reading subreq state. */ + next = smp_load_acquire(&next->next); + if (next == &stream->subrequests) + break; + subreq = list_entry(next, struct netfs_io_subrequest, rreq_link); if (subreq->start + subreq->transferred != start + len || test_bit(NETFS_SREQ_BOUNDARY, &subreq->flags) || diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c index 24fc2bb2f8a4..210eb8f3958d 100644 --- a/fs/netfs/write_collect.c +++ b/fs/netfs/write_collect.c @@ -408,6 +408,16 @@ bool netfs_write_collection(struct netfs_io_request *wreq) netfs_wake_rreq_flag(wreq, NETFS_RREQ_IN_PROGRESS, netfs_rreq_trace_wake_ip); /* As we cleared NETFS_RREQ_IN_PROGRESS, we acquired its ref. */ + switch (wreq->origin) { + case NETFS_WRITEBACK: + case NETFS_WRITEBACK_SINGLE: + case NETFS_WRITETHROUGH: + netfs_wb_end(ictx); + break; + default: + break; + } + if (wreq->iocb) { size_t written = min(wreq->transferred, wreq->len); wreq->iocb->ki_pos += written; diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c index c03c7cc45e47..f2761c99795a 100644 --- a/fs/netfs/write_issue.c +++ b/fs/netfs/write_issue.c @@ -106,7 +106,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping, _enter("R=%x", wreq->debug_id); ictx = netfs_inode(wreq->inode); - if (is_cacheable && netfs_is_cache_enabled(ictx)) + if (is_cacheable) fscache_begin_write_operation(&wreq->cache_resources, netfs_i_cookie(ictx)); if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE) < 0) goto nomem; @@ -551,14 +551,8 @@ int netfs_writepages(struct address_space *mapping, struct folio *folio; int error = 0; - if (!mutex_trylock(&ictx->wb_lock)) { - if (wbc->sync_mode == WB_SYNC_NONE) { - netfs_stat(&netfs_n_wb_lock_skip); - return 0; - } - netfs_stat(&netfs_n_wb_lock_wait); - mutex_lock(&ictx->wb_lock); - } + if (!netfs_wb_begin(ictx, wbc->sync_mode == WB_SYNC_NONE)) + return 0; /* Need the first folio to be able to set up the op. */ folio = writeback_iter(mapping, wbc, NULL, &error); @@ -588,13 +582,13 @@ int netfs_writepages(struct address_space *mapping, } error = netfs_write_folio(wreq, wbc, folio); - if (error < 0) - break; + if (error == -ENOMEM) { + folio_redirty_for_writepage(wbc, folio); + folio_unlock(folio); + } } while ((folio = writeback_iter(mapping, wbc, folio, &error))); netfs_end_issue_write(wreq); - - mutex_unlock(&ictx->wb_lock); netfs_wake_collector(wreq); netfs_put_request(wreq, netfs_rreq_trace_put_return); @@ -602,9 +596,16 @@ int netfs_writepages(struct address_space *mapping, return error; couldnt_start: - netfs_kill_dirty_pages(mapping, wbc, folio); + if (error == -ENOMEM) { + folio_redirty_for_writepage(wbc, folio); + folio_unlock(folio); + folio = writeback_iter(mapping, wbc, folio, &error); + WARN_ON_ONCE(folio != NULL); + } else { + netfs_kill_dirty_pages(mapping, wbc, folio); + } out: - mutex_unlock(&ictx->wb_lock); + netfs_wb_end(ictx); _leave(" = %d", error); return error; } @@ -618,16 +619,17 @@ struct netfs_io_request *netfs_begin_writethrough(struct kiocb *iocb, size_t len struct netfs_io_request *wreq = NULL; struct netfs_inode *ictx = netfs_inode(file_inode(iocb->ki_filp)); - mutex_lock(&ictx->wb_lock); + netfs_wb_begin(ictx, false); wreq = netfs_create_write_req(iocb->ki_filp->f_mapping, iocb->ki_filp, iocb->ki_pos, NETFS_WRITETHROUGH); if (IS_ERR(wreq)) { - mutex_unlock(&ictx->wb_lock); + netfs_wb_end(ictx); return wreq; } wreq->io_streams[0].avail = true; + __set_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &wreq->flags); trace_netfs_write(wreq, netfs_write_trace_writethrough); return wreq; } @@ -685,7 +687,6 @@ int netfs_advance_writethrough(struct netfs_io_request *wreq, struct writeback_c ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_control *wbc, struct folio *writethrough_cache) { - struct netfs_inode *ictx = netfs_inode(wreq->inode); ssize_t ret; _enter("R=%x", wreq->debug_id); @@ -699,8 +700,6 @@ ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_c netfs_end_issue_write(wreq); - mutex_unlock(&ictx->wb_lock); - if (wreq->iocb) ret = -EIOCBQUEUED; else @@ -847,15 +846,10 @@ int netfs_writeback_single(struct address_space *mapping, if (WARN_ON_ONCE(!iov_iter_is_folioq(iter))) return -EIO; - if (!mutex_trylock(&ictx->wb_lock)) { - if (wbc->sync_mode == WB_SYNC_NONE) { - /* The VFS will have undirtied the inode. */ - netfs_single_mark_inode_dirty(&ictx->inode); - netfs_stat(&netfs_n_wb_lock_skip); - return 1; - } - netfs_stat(&netfs_n_wb_lock_wait); - mutex_lock(&ictx->wb_lock); + if (!netfs_wb_begin(ictx, wbc->sync_mode == WB_SYNC_NONE)) { + /* The VFS will have undirtied the inode. */ + netfs_single_mark_inode_dirty(&ictx->inode); + return 1; } wreq = netfs_create_write_req(mapping, NULL, 0, NETFS_WRITEBACK_SINGLE); @@ -893,7 +887,6 @@ int netfs_writeback_single(struct address_space *mapping, smp_wmb(); /* Write lists before ALL_QUEUED. */ set_bit(NETFS_RREQ_ALL_QUEUED, &wreq->flags); - mutex_unlock(&ictx->wb_lock); netfs_wake_collector(wreq); netfs_put_request(wreq, netfs_rreq_trace_put_return); @@ -901,7 +894,7 @@ int netfs_writeback_single(struct address_space *mapping, return ret; couldnt_start: - mutex_unlock(&ictx->wb_lock); + netfs_wb_end(ictx); _leave(" = %d", ret); return ret; } diff --git a/fs/netfs/write_retry.c b/fs/netfs/write_retry.c index 32735abfa03f..058bc7a166a5 100644 --- a/fs/netfs/write_retry.c +++ b/fs/netfs/write_retry.c @@ -72,7 +72,12 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq, !test_bit(NETFS_SREQ_NEED_RETRY, &from->flags)) return; - list_for_each_continue(next, &stream->subrequests) { + for (;;) { + /* Read pointer to subreq before reading subreq state. */ + next = smp_load_acquire(&next->next); + if (next == &stream->subrequests) + break; + subreq = list_entry(next, struct netfs_io_subrequest, rreq_link); if (subreq->start + subreq->transferred != start + len || test_bit(NETFS_SREQ_BOUNDARY, &subreq->flags) || diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index 1fbf832ad165..f2bb56506046 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -38,11 +38,9 @@ static void ntfs_iomap_read_end_io(struct bio *bio) } static void ntfs_iomap_bio_submit_read(const struct iomap_iter *iter, - struct iomap_read_folio_ctx *ctx) + struct iomap_read_folio_ctx *ctx) { - struct bio *bio = ctx->read_ctx; - bio->bi_end_io = ntfs_iomap_read_end_io; - submit_bio(bio); + iomap_bio_submit_read_endio(iter, ctx, ntfs_iomap_read_end_io); } static const struct iomap_read_ops ntfs_iomap_bio_read_ops = { diff --git a/fs/ntfs3/inode.c b/fs/ntfs3/inode.c index c43101cc064d..0c9bd669117d 100644 --- a/fs/ntfs3/inode.c +++ b/fs/ntfs3/inode.c @@ -608,10 +608,7 @@ static void ntfs_iomap_read_end_io(struct bio *bio) static void ntfs_iomap_bio_submit_read(const struct iomap_iter *iter, struct iomap_read_folio_ctx *ctx) { - struct bio *bio = ctx->read_ctx; - - bio->bi_end_io = ntfs_iomap_read_end_io; - submit_bio(bio); + iomap_bio_submit_read_endio(iter, ctx, ntfs_iomap_read_end_io); } static const struct iomap_read_ops ntfs_iomap_bio_read_ops = { diff --git a/fs/orangefs/dir.c b/fs/orangefs/dir.c index 6e2ebc8b9867..115b2c2f5269 100644 --- a/fs/orangefs/dir.c +++ b/fs/orangefs/dir.c @@ -191,7 +191,8 @@ static int fill_from_part(struct orangefs_dir_part *part, { const int offset = sizeof(struct orangefs_readdir_response_s); struct orangefs_khandle *khandle; - __u32 *len, padlen; + __u32 *len; + u64 padlen; loff_t i; char *s; i = ctx->pos & ~PART_MASK; @@ -215,8 +216,8 @@ static int fill_from_part(struct orangefs_dir_part *part, * len is the size of the string itself. padlen is the * total size of the encoded string. */ - padlen = (sizeof *len + *len + 1) + - (8 - (sizeof *len + *len + 1)%8)%8; + padlen = (u64)sizeof *len + *len + 1; + padlen += (8 - padlen % 8) % 8; if (part->len < i + padlen + sizeof *khandle) goto next; s = (void *)part + offset + i + sizeof *len; diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 13cb60b52bd6..e963701b4c87 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -853,7 +853,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) { struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); struct inode *udir = d_inode(c->destdir); - struct dentry *temp, *upper; + struct dentry *temp, *upper, *newdentry = NULL; struct file *tmpfile; int err; @@ -889,6 +889,14 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) err = PTR_ERR(upper); if (!IS_ERR(upper)) { err = ovl_do_link(ofs, temp, udir, upper); + if (!err) { + /* + * Record the linked dentry -- not the disconnected + * O_TMPFILE dentry -- so that ->d_revalidate() on + * the upper fs sees the real parent/name. + */ + newdentry = dget(upper); + } end_creating(upper); } @@ -903,7 +911,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) if (!c->metacopy) ovl_set_upperdata(d_inode(c->dentry)); - ovl_inode_update(d_inode(c->dentry), dget(temp)); + ovl_inode_update(d_inode(c->dentry), newdentry); out: ovl_end_write(c->dentry); diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 00c69707bda9..bc71231cad53 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -783,8 +783,8 @@ static const struct address_space_operations ovl_aops = { * * This chain is valid: * - inode->i_rwsem (inode_lock[2]) - * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) * - OVL_I(inode)->lock (ovl_inode_lock[2]) + * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) * - OVL_I(lowerinode)->lock (ovl_inode_lock[1]) * * And this chain is valid: @@ -797,8 +797,8 @@ static const struct address_space_operations ovl_aops = { * held, because it is in reverse order of the non-nested case using the same * upper fs: * - inode->i_rwsem (inode_lock[1]) - * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) * - OVL_I(inode)->lock (ovl_inode_lock[1]) + * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) */ #define OVL_MAX_NESTING FILESYSTEM_MAX_STACK_DEPTH diff --git a/fs/proc/generic.c b/fs/proc/generic.c index adc9b9a092b0..26086a283672 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -112,6 +112,8 @@ static bool pde_subdir_insert(struct proc_dir_entry *dir, /* Add new node and rebalance tree. */ rb_link_node(&de->subdir_node, parent, new); rb_insert_color(&de->subdir_node, root); + if (S_ISDIR(de->mode)) + dir->nlink++; return true; } @@ -404,7 +406,6 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, write_unlock(&proc_subdir_lock); goto out_free_inum; } - dir->nlink++; write_unlock(&proc_subdir_lock); return dp; @@ -706,6 +707,8 @@ static void pde_erase(struct proc_dir_entry *pde, struct proc_dir_entry *parent) { rb_erase(&pde->subdir_node, &parent->subdir); RB_CLEAR_NODE(&pde->subdir_node); + if (S_ISDIR(pde->mode)) + parent->nlink--; } /* @@ -731,8 +734,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) de = NULL; } else { pde_erase(de, parent); - if (S_ISDIR(de->mode)) - parent->nlink--; } } write_unlock(&proc_subdir_lock); @@ -791,8 +792,6 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) continue; } next = de->parent; - if (S_ISDIR(de->mode)) - next->nlink--; write_unlock(&proc_subdir_lock); proc_entry_rundown(de); diff --git a/fs/resctrl/monitor.c b/fs/resctrl/monitor.c index 0e6a389a16bf..a932a1fea818 100644 --- a/fs/resctrl/monitor.c +++ b/fs/resctrl/monitor.c @@ -135,10 +135,10 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free) struct rdt_resource *r = resctrl_arch_get_resource(RDT_RESOURCE_L3); u32 idx_limit = resctrl_arch_system_num_rmid_idx(); struct rmid_entry *entry; + bool rmid_dirty = true; u32 idx, cur_idx = 1; void *arch_mon_ctx; void *arch_priv; - bool rmid_dirty; u64 val = 0; arch_priv = mon_event_all[QOS_L3_OCCUP_EVENT_ID].arch_priv; @@ -161,22 +161,27 @@ void __check_limbo(struct rdt_l3_mon_domain *d, bool force_free) break; entry = __rmid_entry(idx); - if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid, entry->rmid, - QOS_L3_OCCUP_EVENT_ID, arch_priv, &val, - arch_mon_ctx)) { - rmid_dirty = true; - } else { - rmid_dirty = (val >= resctrl_rmid_realloc_threshold); + if (!force_free) { + if (resctrl_arch_rmid_read(r, &d->hdr, entry->closid, + entry->rmid, QOS_L3_OCCUP_EVENT_ID, + arch_priv, &val, arch_mon_ctx)) { + rmid_dirty = true; + } else { + rmid_dirty = (val >= resctrl_rmid_realloc_threshold); - /* - * x86's CLOSID and RMID are independent numbers, so the entry's - * CLOSID is an empty CLOSID (X86_RESCTRL_EMPTY_CLOSID). On Arm the - * RMID (PMG) extends the CLOSID (PARTID) space with bits that aren't - * used to select the configuration. It is thus necessary to track both - * CLOSID and RMID because there may be dependencies between them - * on some architectures. - */ - trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid, d->hdr.id, val); + /* + * x86's CLOSID and RMID are independent numbers, + * so the entry's CLOSID is an empty CLOSID + * (X86_RESCTRL_EMPTY_CLOSID). On Arm the RMID + * (PMG) extends the CLOSID (PARTID) space with + * bits that aren't used to select the configuration. + * It is thus necessary to track both CLOSID and + * RMID because there may be dependencies between + * them on some architectures. + */ + trace_mon_llc_occupancy_limbo(entry->closid, entry->rmid, + d->hdr.id, val); + } } if (force_free || !rmid_dirty) { diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 901e1340c986..854e672a4e37 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -166,6 +166,6 @@ extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ /* when changing internal version - update following two lines at same time */ -#define SMB3_PRODUCT_BUILD 60 -#define CIFS_VERSION "2.60" +#define SMB3_PRODUCT_BUILD 61 +#define CIFS_VERSION "2.61" #endif /* _CIFSFS_H */ diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 8b25d6c9ec5e..5a25635bc62a 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -241,6 +241,7 @@ static void cifs_issue_read(struct netfs_io_subrequest *subreq) return; failed: + add_credits_and_wake_if(rdata->server, &rdata->credits, 0); subreq->error = rc; netfs_read_subreq_terminated(subreq); } diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index d058584b8f05..95c0efe9d43b 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2396,9 +2396,9 @@ parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *info, memset(posix, 0, sizeof(*posix)); - posix->nlink = le32_to_cpu(*(__le32 *)(beg + 0)); - posix->reparse_tag = le32_to_cpu(*(__le32 *)(beg + 4)); - posix->mode = le32_to_cpu(*(__le32 *)(beg + 8)); + posix->nlink = get_unaligned_le32(beg); + posix->reparse_tag = get_unaligned_le32(beg + 4); + posix->mode = get_unaligned_le32(beg + 8); sid = beg + 12; sid_len = posix_info_sid_size(sid, end); @@ -5405,7 +5405,7 @@ int posix_info_sid_size(const void *beg, const void *end) size_t subauth; int total; - if (beg + 1 > end) + if (beg + 2 > end) return -1; subauth = *(u8 *)(beg+1); diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h index df0554a2c50d..88104f0cf363 100644 --- a/fs/smb/server/ksmbd_work.h +++ b/fs/smb/server/ksmbd_work.h @@ -67,6 +67,13 @@ struct ksmbd_work { /* Number of granted credits */ unsigned int credits_granted; + /* + * Credit charge added to conn->outstanding_credits at receive time + * for the SMB2 PDU currently being processed, pending release. Zero + * once the charge has been returned (on the response or error path). + */ + unsigned short credit_charge; + /* response smb header size */ unsigned int response_sz; diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c index 31dd9f3479b2..3c55ae5d6a11 100644 --- a/fs/smb/server/oplock.c +++ b/fs/smb/server/oplock.c @@ -278,10 +278,24 @@ struct oplock_info *opinfo_get(struct ksmbd_file *fp) return opinfo; } -static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) +struct oplock_snapshot { + bool durable_open; + bool durable_detached; + unsigned long long fid; +}; + +static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci, + struct ksmbd_file *skip_fp, + struct oplock_snapshot *snapshot) { struct oplock_info *opinfo; + if (snapshot) { + snapshot->durable_open = false; + snapshot->durable_detached = false; + snapshot->fid = KSMBD_NO_FID; + } + down_read(&ci->m_lock); opinfo = list_first_entry_or_null(&ci->m_op_list, struct oplock_info, op_entry); @@ -295,6 +309,16 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci) opinfo = NULL; } } + + if (opinfo && snapshot && opinfo->o_fp && + opinfo->o_fp != skip_fp && + READ_ONCE(opinfo->o_fp->is_durable)) { + snapshot->durable_open = true; + snapshot->durable_detached = + !READ_ONCE(opinfo->o_fp->conn) || + !READ_ONCE(opinfo->o_fp->tcon); + snapshot->fid = opinfo->fid; + } } up_read(&ci->m_lock); @@ -314,7 +338,7 @@ void opinfo_put(struct oplock_info *opinfo) static bool ksmbd_inode_has_lease(struct ksmbd_inode *ci) { - struct oplock_info *opinfo = opinfo_get_list(ci); + struct oplock_info *opinfo = opinfo_get_list(ci, NULL, NULL); bool is_lease; if (!opinfo) @@ -1180,6 +1204,36 @@ static int oplock_break(struct oplock_info *brk_opinfo, int req_op_level, return err; } +struct oplock_break_entry { + struct list_head list; + struct oplock_info *opinfo; +}; + +static int oplock_break_add(struct list_head *head, struct oplock_info *opinfo) +{ + struct oplock_break_entry *ent; + + ent = kmalloc_obj(struct oplock_break_entry, KSMBD_DEFAULT_GFP); + if (!ent) + return -ENOMEM; + + ent->opinfo = opinfo; + list_add_tail(&ent->list, head); + return 0; +} + +static void oplock_break_drain_none(struct list_head *head) +{ + struct oplock_break_entry *ent, *tmp; + + list_for_each_entry_safe(ent, tmp, head, list) { + oplock_break(ent->opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL, false); + list_del(&ent->list); + opinfo_put(ent->opinfo); + kfree(ent); + } +} + void destroy_lease_table(struct ksmbd_conn *conn) { struct lease_table *lb, *lbtmp; @@ -1289,6 +1343,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, { struct oplock_info *opinfo; struct ksmbd_inode *p_ci = NULL; + LIST_HEAD(brk_list); if (lctx->version != 2) return; @@ -1314,12 +1369,14 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp, continue; } - oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL, false); - opinfo_put(opinfo); + if (oplock_break_add(&brk_list, opinfo)) + opinfo_put(opinfo); } } up_read(&p_ci->m_lock); + oplock_break_drain_none(&brk_list); + ksmbd_inode_put(p_ci); } @@ -1327,6 +1384,7 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) { struct oplock_info *opinfo; struct ksmbd_inode *p_ci = NULL; + LIST_HEAD(brk_list); rcu_read_lock(); opinfo = rcu_dereference(fp->f_opinfo); @@ -1355,12 +1413,14 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp) continue; } - oplock_break(opinfo, SMB2_OPLOCK_LEVEL_NONE, NULL, false); - opinfo_put(opinfo); + if (oplock_break_add(&brk_list, opinfo)) + opinfo_put(opinfo); } } up_read(&p_ci->m_lock); + oplock_break_drain_none(&brk_list); + ksmbd_inode_put(p_ci); } @@ -1385,6 +1445,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, struct oplock_info *opinfo = NULL, *prev_opinfo = NULL; struct ksmbd_inode *ci = fp->f_ci; struct lease_table *new_lb = NULL; + struct oplock_snapshot prev_op_snapshot; bool prev_op_has_lease; bool prev_durable_open = false; bool prev_durable_detached = false; @@ -1452,7 +1513,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, goto out; } } - prev_opinfo = opinfo_get_list(ci); + prev_opinfo = opinfo_get_list(ci, fp, &prev_op_snapshot); if (!prev_opinfo || (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) { opinfo_put(prev_opinfo); @@ -1474,13 +1535,9 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid, goto op_break_not_needed; } - if (prev_opinfo->o_fp && prev_opinfo->o_fp != fp && - prev_opinfo->o_fp->is_durable) { - prev_durable_open = true; - prev_durable_detached = !prev_opinfo->o_fp->conn || - !prev_opinfo->o_fp->tcon; - prev_fid = prev_opinfo->fid; - } + prev_durable_open = prev_op_snapshot.durable_open; + prev_durable_detached = prev_op_snapshot.durable_detached; + prev_fid = prev_op_snapshot.fid; err = oplock_break(prev_opinfo, break_level, work, share_ret < 0 && prev_opinfo->is_lease); @@ -1571,7 +1628,7 @@ static bool smb_break_all_write_oplock(struct ksmbd_work *work, struct oplock_info *brk_opinfo; bool sent_break = false; - brk_opinfo = opinfo_get_list(fp->f_ci); + brk_opinfo = opinfo_get_list(fp->f_ci, NULL, NULL); if (!brk_opinfo) return false; if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH && @@ -1602,9 +1659,11 @@ static void __smb_break_all_levII_oplock(struct ksmbd_work *work, bool send_interim, bool send_oplock_break) { struct oplock_info *op, *brk_op; + struct oplock_break_entry *ent, *tmp; struct ksmbd_inode *ci; struct ksmbd_conn *conn = work->conn; bool sent_interim = false; + LIST_HEAD(brk_list); if (!test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_OPLOCKS)) @@ -1646,6 +1705,22 @@ static void __smb_break_all_levII_oplock(struct ksmbd_work *work, SMB2_LEASE_KEY_SIZE)) goto next; brk_op->open_trunc = is_trunc; + + /* + * Defer the break until ci->m_lock is released: oplock_break() + * may block waiting for the lease break acknowledgment, and the + * close that wakes that wait needs ci->m_lock for write. + */ + if (!oplock_break_add(&brk_list, brk_op)) + continue; +next: + opinfo_put(brk_op); + } + up_read(&ci->m_lock); + + list_for_each_entry_safe(ent, tmp, &brk_list, list) { + brk_op = ent->opinfo; + if (!brk_op->is_lease && !send_oplock_break) { brk_op->level = SMB2_OPLOCK_LEVEL_NONE; brk_op->op_state = OPLOCK_STATE_NONE; @@ -1657,10 +1732,10 @@ static void __smb_break_all_levII_oplock(struct ksmbd_work *work, false); } sent_interim = true; -next: + list_del(&ent->list); opinfo_put(brk_op); + kfree(ent); } - up_read(&ci->m_lock); if (op) opinfo_put(op); diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c index 36feda7e0942..36a5ea4828ad 100644 --- a/fs/smb/server/server.c +++ b/fs/smb/server/server.c @@ -242,6 +242,20 @@ static void __handle_ksmbd_work(struct ksmbd_work *work, } while (is_chained == true); send: + /* + * Release any credit charge still outstanding for this request. On + * the normal path smb2_set_rsp_credits() already returned it, but the + * abort, error and send-no-response paths skip that call, so the + * charge would otherwise leak and eventually exhaust the connection's + * outstanding credit window. + */ + if (work->credit_charge) { + spin_lock(&conn->credits_lock); + conn->outstanding_credits -= work->credit_charge; + work->credit_charge = 0; + spin_unlock(&conn->credits_lock); + } + if (work->tcon) ksmbd_tree_connect_put(work->tcon); smb3_preauth_hash_rsp(work); diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c index a1ddca21c47b..c0c4edd092c2 100644 --- a/fs/smb/server/smb2misc.c +++ b/fs/smb/server/smb2misc.c @@ -261,8 +261,12 @@ static int smb2_calc_size(void *buf, unsigned int *len) static inline int smb2_query_info_req_len(struct smb2_query_info_req *h) { - return le32_to_cpu(h->InputBufferLength) + - le32_to_cpu(h->OutputBufferLength); + return le32_to_cpu(h->InputBufferLength); +} + +static inline int smb2_query_info_resp_len(struct smb2_query_info_req *h) +{ + return le32_to_cpu(h->OutputBufferLength); } static inline int smb2_set_info_req_len(struct smb2_set_info_req *h) @@ -297,9 +301,10 @@ static inline int smb2_ioctl_resp_len(struct smb2_ioctl_req *h) le32_to_cpu(h->MaxOutputResponse); } -static int smb2_validate_credit_charge(struct ksmbd_conn *conn, +static int smb2_validate_credit_charge(struct ksmbd_work *work, struct smb2_hdr *hdr) { + struct ksmbd_conn *conn = work->conn; unsigned int req_len = 0, expect_resp_len = 0, calc_credit_num, max_len; unsigned short credit_charge = le16_to_cpu(hdr->CreditCharge); void *__hdr = hdr; @@ -308,6 +313,7 @@ static int smb2_validate_credit_charge(struct ksmbd_conn *conn, switch (hdr->Command) { case SMB2_QUERY_INFO: req_len = smb2_query_info_req_len(__hdr); + expect_resp_len = smb2_query_info_resp_len(__hdr); break; case SMB2_SET_INFO: req_len = smb2_set_info_req_len(__hdr); @@ -356,8 +362,10 @@ static int smb2_validate_credit_charge(struct ksmbd_conn *conn, ksmbd_debug(SMB, "Limits exceeding the maximum allowable outstanding requests, given : %u, pending : %u\n", credit_charge, conn->outstanding_credits); ret = 1; - } else + } else { conn->outstanding_credits += credit_charge; + work->credit_charge = credit_charge; + } spin_unlock(&conn->credits_lock); @@ -460,7 +468,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work) validate_credit: if ((work->conn->vals->req_capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) && - smb2_validate_credit_charge(work->conn, hdr)) + smb2_validate_credit_charge(work, hdr)) return 1; return 0; diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 5859fa68bb84..097f51fc7ed6 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -363,6 +363,7 @@ int smb2_set_rsp_credits(struct ksmbd_work *work) conn->total_credits -= credit_charge; conn->outstanding_credits -= credit_charge; + work->credit_charge = 0; credits_requested = max_t(unsigned short, le16_to_cpu(req_hdr->CreditRequest), 1); @@ -6920,16 +6921,18 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, } case FILE_LINK_INFORMATION: { - if (!(fp->daccess & FILE_DELETE_LE)) { - pr_err("no right to delete : 0x%x\n", fp->daccess); - return -EACCES; - } + struct smb2_file_link_info *file_info; if (buf_len < sizeof(struct smb2_file_link_info)) return -EMSGSIZE; - return smb2_create_link(work, work->tcon->share_conf, - (struct smb2_file_link_info *)buffer, + file_info = (struct smb2_file_link_info *)buffer; + if (file_info->ReplaceIfExists && !(fp->daccess & FILE_DELETE_LE)) { + pr_err("no right to delete : 0x%x\n", fp->daccess); + return -EACCES; + } + + return smb2_create_link(work, work->tcon->share_conf, file_info, buf_len, fp->filp, work->conn->local_nls); } @@ -7324,7 +7327,7 @@ int smb2_read(struct ksmbd_work *work) ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", fp->filp, offset, length); - aux_payload_buf = kvzalloc(ALIGN(length, 8), KSMBD_DEFAULT_GFP); + aux_payload_buf = kvmalloc(ALIGN(length, 8), KSMBD_DEFAULT_GFP); if (!aux_payload_buf) { err = -ENOMEM; goto out; diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c index 340ea98fa494..9c59c8f73b66 100644 --- a/fs/smb/server/smbacl.c +++ b/fs/smb/server/smbacl.c @@ -374,6 +374,7 @@ static void parse_dacl(struct mnt_idmap *idmap, { int i, ret; u16 num_aces = 0; + u16 dacl_size; unsigned int acl_size; char *acl_base; struct smb_ace **ppace; @@ -403,7 +404,11 @@ static void parse_dacl(struct mnt_idmap *idmap, if (num_aces <= 0) return; - if (num_aces > (le16_to_cpu(pdacl->size) - sizeof(struct smb_acl)) / + dacl_size = le16_to_cpu(pdacl->size); + if (dacl_size < sizeof(struct smb_acl)) + return; + + if (num_aces > (dacl_size - sizeof(struct smb_acl)) / (offsetof(struct smb_ace, sid) + offsetof(struct smb_sid, sub_auth) + sizeof(__le16))) return; @@ -740,12 +745,18 @@ static void set_ntacl_dacl(struct mnt_idmap *idmap, if (nt_ace_size > aces_size) break; + if (ntace->sid.num_subauth == 0 || + ntace->sid.num_subauth > SID_MAX_SUB_AUTHORITIES) + goto next_ace; + memcpy((char *)pndace + size, ntace, nt_ace_size); if (check_add_overflow(size, nt_ace_size, &size)) break; + num_aces++; + +next_ace: aces_size -= nt_ace_size; ntace = (struct smb_ace *)((char *)ntace + nt_ace_size); - num_aces++; } } diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index f5fa22d87603..d0a0ad15d803 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -1487,8 +1487,8 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn, if (rc < 0) pr_err("Failed to store XATTR ntacl :%d\n", rc); - kfree(sd_ndr.data); out: + kfree(sd_ndr.data); kfree(acl_ndr.data); kfree(smb_acl); kfree(def_smb_acl); @@ -1504,7 +1504,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, struct ndr n; struct inode *inode = d_inode(dentry); struct ndr acl_ndr = {0}; - struct xattr_ntacl acl; + struct xattr_ntacl acl = {0}; struct xattr_smb_acl *smb_acl = NULL, *def_smb_acl = NULL; __u8 cmp_hash[XATTR_SD_HASH_SIZE] = {0}; @@ -1515,7 +1515,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, n.length = rc; rc = ndr_decode_v4_ntacl(&n, &acl); if (rc) - goto free_n_data; + goto out_free; smb_acl = ksmbd_vfs_make_xattr_posix_acl(idmap, inode, ACL_TYPE_ACCESS); @@ -1541,6 +1541,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, *pntsd = acl.sd_buf; if (acl.sd_size < sizeof(struct smb_ntsd)) { pr_err("sd size is invalid\n"); + rc = -EINVAL; goto out_free; } @@ -1560,8 +1561,6 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn, kfree(acl.sd_buf); *pntsd = NULL; } - -free_n_data: kfree(n.data); return rc; } @@ -1576,14 +1575,15 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap, err = ndr_encode_dos_attr(&n, da); if (err) - return err; + goto out; err = ksmbd_vfs_setxattr(idmap, path, XATTR_NAME_DOS_ATTRIBUTE, (void *)n.data, n.offset, 0, get_write); if (err) ksmbd_debug(SMB, "failed to store dos attribute in xattr\n"); - kfree(n.data); +out: + kfree(n.data); return err; } diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c index fde22742d193..d95c405eab11 100644 --- a/fs/smb/server/vfs_cache.c +++ b/fs/smb/server/vfs_cache.c @@ -581,7 +581,20 @@ bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry) if (fp->conn || !fp->is_durable || fp->f_state != FP_INITED) continue; - list_move_tail(&fp->node, &dispose); + + /* + * Claim the close before unlinking fp from m_fp_list. + * refcount == 1 means only the durable lifetime ref is + * left. Add a transient ref so final close can drop both. + */ + write_lock(&global_ft.lock); + if (atomic_read(&fp->refcount) == 1) { + atomic_inc(&fp->refcount); + __ksmbd_remove_durable_fd(fp); + ksmbd_mark_fp_closed(fp); + list_move_tail(&fp->node, &dispose); + } + write_unlock(&global_ft.lock); } } up_write(&ci->m_lock); @@ -589,16 +602,18 @@ bool ksmbd_close_disconnected_durable_delete_on_close(struct dentry *dentry) /* * Drop our lookup reference before closing so the last __ksmbd_close_fd() * can drop m_count to zero and unlink the delete-on-close file. The - * collected handles still hold references, so ci stays valid until they - * are closed below. + * collected handles still hold the transient reference taken above, so + * ci stays valid until they are closed below. */ ksmbd_inode_put(ci); while (!list_empty(&dispose)) { fp = list_first_entry(&dispose, struct ksmbd_file, node); list_del_init(&fp->node); - __ksmbd_close_fd(NULL, fp); - closed = true; + if (atomic_sub_and_test(2, &fp->refcount)) { + __ksmbd_close_fd(NULL, fp); + closed = true; + } } return closed; @@ -838,19 +853,24 @@ int ksmbd_close_fd_app_instance_id(char *app_instance_id) return 0; opinfo = opinfo_get(fp); - if (!opinfo || !opinfo->sess) + if (!opinfo) goto out; + down_read(&fp->f_ci->m_lock); + if (!opinfo->conn) { + up_read(&fp->f_ci->m_lock); + goto out; + } + ft = &opinfo->sess->file_table; write_lock(&ft->lock); - if (fp->f_state == FP_INITED) { - if (has_file_id(fp->volatile_id)) { - idr_remove(ft->idr, fp->volatile_id); - fp->volatile_id = KSMBD_NO_FID; - } + if (fp->f_state == FP_INITED && has_file_id(fp->volatile_id)) { + idr_remove(ft->idr, fp->volatile_id); + fp->volatile_id = KSMBD_NO_FID; n_to_drop = ksmbd_mark_fp_closed(fp); } write_unlock(&ft->lock); + up_read(&fp->f_ci->m_lock); opinfo_put(opinfo); opinfo = NULL; @@ -1461,16 +1481,21 @@ void ksmbd_stop_durable_scavenger(void) static int ksmbd_vfs_copy_durable_owner(struct ksmbd_file *fp, struct ksmbd_user *user) { + char *name; + if (!user) return -EINVAL; /* Duplicate the user name to ensure identity persistence */ - fp->owner.name = kstrdup(user->name, GFP_KERNEL); - if (!fp->owner.name) + name = kstrdup(user->name, GFP_KERNEL); + if (!name) return -ENOMEM; + spin_lock(&fp->f_lock); fp->owner.uid = user->uid; fp->owner.gid = user->gid; + fp->owner.name = name; + spin_unlock(&fp->f_lock); return 0; } @@ -1488,18 +1513,24 @@ static int ksmbd_vfs_copy_durable_owner(struct ksmbd_file *fp, bool ksmbd_vfs_compare_durable_owner(struct ksmbd_file *fp, struct ksmbd_user *user) { - if (!user || !fp->owner.name) + bool ret = false; + + if (!user) return false; + spin_lock(&fp->f_lock); + if (!fp->owner.name) + goto out; + /* Check if the UID and GID match first (fast path) */ if (fp->owner.uid != user->uid || fp->owner.gid != user->gid) - return false; + goto out; /* Validate the account name to ensure the same SecurityContext */ - if (strcmp(fp->owner.name, user->name)) - return false; - - return true; + ret = (strcmp(fp->owner.name, user->name) == 0); +out: + spin_unlock(&fp->f_lock); + return ret; } static bool session_fd_check(struct ksmbd_tree_connect *tcon, @@ -1530,11 +1561,13 @@ static bool session_fd_check(struct ksmbd_tree_connect *tcon, conn = fp->conn; ci = fp->f_ci; down_write(&ci->m_lock); - list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { + list_for_each_entry_rcu(op, &ci->m_op_list, op_entry, + lockdep_is_held(&ci->m_lock)) { if (op->conn != conn) continue; ksmbd_conn_put(op->conn); op->conn = NULL; + op->sess = NULL; } up_write(&ci->m_lock); @@ -1685,16 +1718,20 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp) ci = fp->f_ci; down_write(&ci->m_lock); - list_for_each_entry_rcu(op, &ci->m_op_list, op_entry) { + list_for_each_entry_rcu(op, &ci->m_op_list, op_entry, + lockdep_is_held(&ci->m_lock)) { if (op->conn) continue; op->conn = ksmbd_conn_get(fp->conn); + op->sess = work->sess; } up_write(&ci->m_lock); + spin_lock(&fp->f_lock); fp->owner.uid = fp->owner.gid = 0; kfree(fp->owner.name); fp->owner.name = NULL; + spin_unlock(&fp->f_lock); return 0; } diff --git a/fs/xfs/libxfs/xfs_dquot_buf.c b/fs/xfs/libxfs/xfs_dquot_buf.c index ce767b40482f..bbada0d3cc08 100644 --- a/fs/xfs/libxfs/xfs_dquot_buf.c +++ b/fs/xfs/libxfs/xfs_dquot_buf.c @@ -436,17 +436,27 @@ xfs_dqinode_metadir_create( error = xfs_metadir_create(&upd, S_IFREG); if (error) - return error; + goto out_cancel; xfs_trans_log_inode(upd.tp, upd.ip, XFS_ILOG_CORE); error = xfs_metadir_commit(&upd); if (error) - return error; + goto out_irele; xfs_finish_inode_setup(upd.ip); *ipp = upd.ip; return 0; + +out_cancel: + xfs_metadir_cancel(&upd, error); +out_irele: + /* Have to finish setting up the inode to ensure it's deleted. */ + if (upd.ip) { + xfs_finish_inode_setup(upd.ip); + xfs_irele(upd.ip); + } + return error; } #ifndef __KERNEL__ diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c index 7114c9a44182..2554494847ff 100644 --- a/fs/xfs/scrub/agheader_repair.c +++ b/fs/xfs/scrub/agheader_repair.c @@ -652,7 +652,7 @@ xrep_agfl_fill( while (agbno < start + len && af->fl_off < af->flcount) af->agfl_bno[af->fl_off++] = cpu_to_be32(agbno++); - error = xagb_bitmap_set(&af->used_extents, start, agbno - 1); + error = xagb_bitmap_set(&af->used_extents, start, agbno - start); if (error) return error; diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 2a0c54256e93..51293b6f331f 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -764,8 +764,7 @@ xfs_bio_submit_read( /* defer read completions to the ioend workqueue */ iomap_init_ioend(iter->inode, bio, ctx->read_ctx_file_offset, 0); - bio->bi_end_io = xfs_end_bio; - submit_bio(bio); + iomap_bio_submit_read_endio(iter, ctx, xfs_end_bio); } static const struct iomap_read_ops xfs_iomap_read_ops = { diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index 3ce12fe1c307..e1465e950acc 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -120,6 +120,22 @@ xfs_buf_free( call_rcu(&bp->b_rcu, xfs_buf_free_callback); } +static int +xfs_buf_alloc_folio( + struct xfs_buf *bp, + size_t size, + gfp_t gfp_mask) +{ + struct folio *folio; + + folio = folio_alloc(gfp_mask, get_order(size)); + if (!folio) + return -ENOMEM; + bp->b_addr = folio_address(folio); + trace_xfs_buf_backing_folio(bp, _RET_IP_); + return 0; +} + static int xfs_buf_alloc_kmem( struct xfs_buf *bp, @@ -129,7 +145,7 @@ xfs_buf_alloc_kmem( ASSERT(is_power_of_2(size)); ASSERT(size < PAGE_SIZE); - bp->b_addr = kmalloc(size, gfp_mask | __GFP_NOFAIL); + bp->b_addr = kmalloc(size, gfp_mask); if (!bp->b_addr) return -ENOMEM; @@ -148,6 +164,26 @@ xfs_buf_alloc_kmem( return 0; } +static int +xfs_buf_alloc_vmalloc( + struct xfs_buf *bp, + size_t size, + gfp_t gfp_mask) +{ + for (;;) { + bp->b_addr = __vmalloc(size, gfp_mask); + if (bp->b_addr) + break; + if (gfp_mask & __GFP_NORETRY) + return -ENOMEM; + XFS_STATS_INC(bp->b_mount, xb_page_retries); + memalloc_retry_wait(gfp_mask); + } + + trace_xfs_buf_backing_vmalloc(bp, _RET_IP_); + return 0; +} + /* * Allocate backing memory for a buffer. * @@ -175,7 +211,6 @@ xfs_buf_alloc_backing_mem( { size_t size = BBTOB(bp->b_length); gfp_t gfp_mask = GFP_KERNEL | __GFP_NOLOCKDEP | __GFP_NOWARN; - struct folio *folio; if (xfs_buftarg_is_mem(bp->b_target)) return xmbuf_map_backing_mem(bp); @@ -187,22 +222,6 @@ xfs_buf_alloc_backing_mem( if (flags & XBF_READ_AHEAD) gfp_mask |= __GFP_NORETRY; - /* - * For buffers smaller than PAGE_SIZE use a kmalloc allocation if that - * is properly aligned. The slab allocator now guarantees an aligned - * allocation for all power of two sizes, which matches most of the - * smaller than PAGE_SIZE buffers used by XFS. - */ - if (size < PAGE_SIZE && is_power_of_2(size)) - return xfs_buf_alloc_kmem(bp, size, gfp_mask); - - /* - * Don't bother with the retry loop for single PAGE allocations: vmalloc - * won't do any better. - */ - if (size <= PAGE_SIZE) - gfp_mask |= __GFP_NOFAIL; - /* * Optimistically attempt a single high order folio allocation for * larger than PAGE_SIZE buffers. @@ -215,35 +234,31 @@ xfs_buf_alloc_backing_mem( * path for them instead of wasting memory here. */ if (size > PAGE_SIZE) { - if (!is_power_of_2(size)) - goto fallback; - gfp_mask &= ~__GFP_DIRECT_RECLAIM; - gfp_mask |= __GFP_NORETRY; - } - folio = folio_alloc(gfp_mask, get_order(size)); - if (!folio) { - if (size <= PAGE_SIZE) - return -ENOMEM; - trace_xfs_buf_backing_fallback(bp, _RET_IP_); - goto fallback; - } - bp->b_addr = folio_address(folio); - trace_xfs_buf_backing_folio(bp, _RET_IP_); - return 0; + if (is_power_of_2(size)) { + gfp_t folio_gfp = gfp_mask; -fallback: - for (;;) { - bp->b_addr = __vmalloc(size, gfp_mask); - if (bp->b_addr) - break; - if (flags & XBF_READ_AHEAD) - return -ENOMEM; - XFS_STATS_INC(bp->b_mount, xb_page_retries); - memalloc_retry_wait(gfp_mask); + folio_gfp &= ~__GFP_DIRECT_RECLAIM; + folio_gfp |= __GFP_NORETRY; + if (xfs_buf_alloc_folio(bp, size, folio_gfp) == 0) + return 0; + trace_xfs_buf_backing_fallback(bp, _RET_IP_); + } + return xfs_buf_alloc_vmalloc(bp, size, gfp_mask); } - trace_xfs_buf_backing_vmalloc(bp, _RET_IP_); - return 0; + /* + * The slab allocator now guarantees aligned allocations for all power + * of two sizes. This covers most smaller XFS buffers, so just use + * kmalloc in this case. + * + * Don't bother with the vmalloc fallback for allocations of page size + * or less: vmalloc won't do any better. + */ + if (!(gfp_mask & __GFP_NORETRY)) + gfp_mask |= __GFP_NOFAIL; + if (size < PAGE_SIZE && is_power_of_2(size)) + return xfs_buf_alloc_kmem(bp, size, gfp_mask); + return xfs_buf_alloc_folio(bp, size, gfp_mask); } static int @@ -1083,11 +1098,17 @@ xfs_buf_ioend_handle_error( return false; } -/* returns false if the caller needs to resubmit the I/O, else true */ -static bool -__xfs_buf_ioend( +/* + * Complete a buffer read or write. + * + * Releases the buffer if the I/O was asynchronous. + */ +static void +xfs_buf_ioend( struct xfs_buf *bp) { + bool async = bp->b_flags & XBF_ASYNC; + trace_xfs_buf_iodone(bp, _RET_IP_); if (bp->b_flags & XBF_READ) { @@ -1101,14 +1122,16 @@ __xfs_buf_ioend( if (bp->b_flags & XBF_READ_AHEAD) percpu_counter_dec(&bp->b_target->bt_readahead_count); } else { - if (!bp->b_error) { + if (unlikely(bp->b_error)) { + if (xfs_buf_ioend_handle_error(bp)) { + ASSERT(async); + return; + } + } else { bp->b_flags &= ~XBF_WRITE_FAIL; bp->b_flags |= XBF_DONE; } - if (unlikely(bp->b_error) && xfs_buf_ioend_handle_error(bp)) - return false; - /* clear the retry state */ bp->b_last_error = 0; bp->b_retries = 0; @@ -1128,30 +1151,15 @@ __xfs_buf_ioend( bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD | _XBF_LOGRECOVERY); - return true; -} - -static void -xfs_buf_ioend( - struct xfs_buf *bp) -{ - if (!__xfs_buf_ioend(bp)) - return; - if (bp->b_flags & XBF_ASYNC) + if (async) xfs_buf_relse(bp); - else - complete(&bp->b_iowait); } static void xfs_buf_ioend_work( struct work_struct *work) { - struct xfs_buf *bp = - container_of(work, struct xfs_buf, b_ioend_work); - - if (__xfs_buf_ioend(bp)) - xfs_buf_relse(bp); + xfs_buf_ioend(container_of(work, struct xfs_buf, b_ioend_work)); } void @@ -1177,17 +1185,18 @@ xfs_buf_ioerror_alert( } /* - * To simulate an I/O failure, the buffer must be locked and held with at least - * two references. + * Fail a locked and referenced buffer outside the I/O path. * - * The buf item reference is dropped via ioend processing. The second reference - * is owned by the caller and is dropped on I/O completion if the buffer is - * XBF_ASYNC. + * The caller transfers a reference which will be released after processing the + * error. */ void -xfs_buf_ioend_fail( +xfs_buf_fail( struct xfs_buf *bp) { + ASSERT(xfs_buf_islocked(bp)); + + bp->b_flags |= XBF_ASYNC; bp->b_flags &= ~XBF_DONE; xfs_buf_stale(bp); xfs_buf_ioerror(bp, -EIO); @@ -1300,12 +1309,11 @@ xfs_buf_iowait( { ASSERT(!(bp->b_flags & XBF_ASYNC)); - do { - trace_xfs_buf_iowait(bp, _RET_IP_); - wait_for_completion(&bp->b_iowait); - trace_xfs_buf_iowait_done(bp, _RET_IP_); - } while (!__xfs_buf_ioend(bp)); + trace_xfs_buf_iowait(bp, _RET_IP_); + wait_for_completion(&bp->b_iowait); + trace_xfs_buf_iowait_done(bp, _RET_IP_); + xfs_buf_ioend(bp); return bp->b_error; } @@ -1369,8 +1377,8 @@ xfs_buf_submit( * on shutdown. */ if (bp->b_mount->m_log && xlog_is_shutdown(bp->b_mount->m_log)) { - xfs_buf_ioend_fail(bp); - return; + xfs_buf_ioerror(bp, -EIO); + goto ioerror; } if (bp->b_flags & XBF_WRITE) @@ -1383,18 +1391,26 @@ xfs_buf_submit( bp->b_error = 0; if ((bp->b_flags & XBF_WRITE) && !xfs_buf_verify_write(bp)) { + /* ->verify_write should have set b_error already */ xfs_force_shutdown(bp->b_mount, SHUTDOWN_CORRUPT_INCORE); - xfs_buf_ioend(bp); - return; + goto ioerror; } /* In-memory targets are directly mapped, no I/O required. */ - if (xfs_buftarg_is_mem(bp->b_target)) { - xfs_buf_ioend(bp); - return; - } + if (xfs_buftarg_is_mem(bp->b_target)) + goto end_io; xfs_buf_submit_bio(bp); + return; + +ioerror: + bp->b_flags &= ~XBF_DONE; + xfs_buf_stale(bp); +end_io: + if (bp->b_flags & XBF_ASYNC) + xfs_buf_ioend(bp); + else + complete(&bp->b_iowait); } /* diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index b3cd1c7029f1..79cc9c3f0254 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h @@ -290,7 +290,7 @@ extern void __xfs_buf_ioerror(struct xfs_buf *bp, int error, xfs_failaddr_t failaddr); #define xfs_buf_ioerror(bp, err) __xfs_buf_ioerror((bp), (err), __this_address) extern void xfs_buf_ioerror_alert(struct xfs_buf *bp, xfs_failaddr_t fa); -void xfs_buf_ioend_fail(struct xfs_buf *); +void xfs_buf_fail(struct xfs_buf *bp); void __xfs_buf_mark_corrupt(struct xfs_buf *bp, xfs_failaddr_t fa); #define xfs_buf_mark_corrupt(bp) __xfs_buf_mark_corrupt((bp), __this_address) diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 8487635579e5..1f055cd6732e 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -549,8 +549,7 @@ xfs_buf_item_unpin( * wait for the lock and then run the IO failure completion. */ xfs_buf_lock(bp); - bp->b_flags |= XBF_ASYNC; - xfs_buf_ioend_fail(bp); + xfs_buf_fail(bp); return; } diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 317eb57f989f..15279d22a894 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -2646,8 +2646,7 @@ xfs_iflush_cluster( * inode cluster buffers. */ xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - bp->b_flags |= XBF_ASYNC; - xfs_buf_ioend_fail(bp); + xfs_buf_fail(bp); return error; } diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 09e6678ca487..5f984bf5698a 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1028,7 +1028,7 @@ xlog_verify_head( { struct xlog_rec_header *tmp_rhead; char *tmp_buffer; - xfs_daddr_t first_bad; + xfs_daddr_t first_bad = XFS_BUF_DADDR_NULL; xfs_daddr_t tmp_rhead_blk; int found; int error; @@ -1057,7 +1057,8 @@ xlog_verify_head( */ error = xlog_do_recovery_pass(log, *head_blk, tmp_rhead_blk, XLOG_RECOVER_CRCPASS, &first_bad); - if ((error == -EFSBADCRC || error == -EFSCORRUPTED) && first_bad) { + if ((error == -EFSBADCRC || error == -EFSCORRUPTED) && + first_bad != XFS_BUF_DADDR_NULL) { /* * We've hit a potential torn write. Reset the error and warn * about it. @@ -3575,4 +3576,3 @@ xlog_recover_cancel( if (xlog_recovery_needed(log)) xlog_recover_cancel_intents(log); } - diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index aa0d2976f1c3..896b24f87ac9 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -166,10 +166,9 @@ xfs_qm_dqpurge( * does it on success. */ error = xfs_qm_dqflush(dqp, bp); - if (!error) { + if (!error) error = xfs_bwrite(bp); - xfs_buf_relse(bp); - } + xfs_buf_relse(bp); xfs_dqflock(dqp); } xfs_dquot_detach_buf(dqp); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index eac7f9503805..8531d526fc44 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -534,8 +534,11 @@ xfs_open_devices( out_free_rtdev_targ: if (mp->m_rtdev_targp) xfs_free_buftarg(mp->m_rtdev_targp); + mp->m_rtdev_targp = NULL; + rtdev_file = NULL; /* released by xfs_free_buftarg() */ out_free_ddev_targ: xfs_free_buftarg(mp->m_ddev_targp); + mp->m_ddev_targp = NULL; out_close_rtdev: if (rtdev_file) bdev_fput(rtdev_file); diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index aeb74e2f9d4f..760e1ded325c 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -134,6 +134,7 @@ static inline void acpi_os_terminate_debugger(void) /* * OSL interfaces added by Linux */ +#define acpi_ut_safe_strncpy strscpy_pad #endif /* __KERNEL__ */ diff --git a/include/drm/display/drm_dp_helper.h b/include/drm/display/drm_dp_helper.h index 8c2d77a032f0..ab16c1be3900 100644 --- a/include/drm/display/drm_dp_helper.h +++ b/include/drm/display/drm_dp_helper.h @@ -115,6 +115,7 @@ struct drm_dp_vsc_sdp { * @duration_decr_ms: Successive frame duration decrease * @target_rr_divider: Target refresh rate divider * @mode: Adaptive Sync Operation Mode + * @coasting_vtotal: Coasting vtotal */ struct drm_dp_as_sdp { unsigned char sdp_type; diff --git a/include/drm/drm_fixed.h b/include/drm/drm_fixed.h index 33de514a5221..21d822aeed55 100644 --- a/include/drm/drm_fixed.h +++ b/include/drm/drm_fixed.h @@ -79,7 +79,8 @@ static inline u32 dfixed_div(fixed20_12 A, fixed20_12 B) #define DRM_FIXED_ALMOST_ONE (DRM_FIXED_ONE - DRM_FIXED_EPSILON) /** - * @drm_sm2fixp + * drm_sm2fixp() - convert signed-magnitude to fixed point + * @a: 1.31.32 signed-magnitude fixed point * * Convert a 1.31.32 signed-magnitude fixed point to 32.32 * 2s-complement fixed point diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index b9bb92e4b029..6e3eccc3c349 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -193,6 +193,7 @@ enum drm_mode_status { #define DRM_MODE_MATCH_FLAGS (1 << 2) #define DRM_MODE_MATCH_3D_FLAGS (1 << 3) #define DRM_MODE_MATCH_ASPECT_RATIO (1 << 4) +#define DRM_MODE_MATCH_TIMINGS_VRR (1 << 5) /** * struct drm_display_mode - DRM kernel-internal display mode structure diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h index f2a787bc4f64..0beede3ddc4e 100644 --- a/include/drm/drm_ras.h +++ b/include/drm/drm_ras.h @@ -6,6 +6,8 @@ #ifndef __DRM_RAS_H__ #define __DRM_RAS_H__ +#include + #include /** diff --git a/include/drm/intel/display_parent_interface.h b/include/drm/intel/display_parent_interface.h index 39991afeb173..de395df9ca30 100644 --- a/include/drm/intel/display_parent_interface.h +++ b/include/drm/intel/display_parent_interface.h @@ -167,7 +167,9 @@ struct intel_display_overlay_interface { struct intel_display_panic_interface { struct intel_panic *(*alloc)(void); - int (*setup)(struct intel_panic *panic, struct drm_scanout_buffer *sb); + int (*setup)(struct intel_panic *panic, struct drm_scanout_buffer *sb, + struct drm_gem_object *obj, + unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width)); void (*finish)(struct intel_panic *panic); }; diff --git a/include/drm/intel/mchbar_regs.h b/include/drm/intel/mchbar_regs.h index ca0d421be16c..66498ca5e40b 100644 --- a/include/drm/intel/mchbar_regs.h +++ b/include/drm/intel/mchbar_regs.h @@ -6,8 +6,6 @@ #ifndef __INTEL_MCHBAR_REGS__ #define __INTEL_MCHBAR_REGS__ -#include "i915_reg_defs.h" - /* * MCHBAR mirror. * diff --git a/include/drm/intel/pciids.h b/include/drm/intel/pciids.h index e32ef763427c..dff389b56eb3 100644 --- a/include/drm/intel/pciids.h +++ b/include/drm/intel/pciids.h @@ -893,8 +893,9 @@ MACRO__(0xD741, ## __VA_ARGS__), \ MACRO__(0xD742, ## __VA_ARGS__), \ MACRO__(0xD743, ## __VA_ARGS__), \ - MACRO__(0xD744, ## __VA_ARGS__), \ - MACRO__(0xD745, ## __VA_ARGS__) + MACRO__(0xD745, ## __VA_ARGS__), \ + MACRO__(0xD74A, ## __VA_ARGS__), \ + MACRO__(0xD74B, ## __VA_ARGS__) /* CRI */ #define INTEL_CRI_IDS(MACRO__, ...) \ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 10d6c6c11bdf..60ab50cb8930 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -13,7 +13,7 @@ #include /* for struct resource */ #include #include -#include +#include #include #include #include diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h index 6c54d5c0d21f..80a74cd2da7e 100644 --- a/include/linux/amba/bus.h +++ b/include/linux/amba/bus.h @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h index 4e1ad8ccbcdd..de0ecd0fb05a 100644 --- a/include/linux/auxiliary_bus.h +++ b/include/linux/auxiliary_bus.h @@ -9,7 +9,7 @@ #define _AUXILIARY_BUS_H_ #include -#include +#include /** * DOC: DEVICE_LIFESPAN diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 60b94b944e9f..f02cb3909375 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -3,7 +3,7 @@ #define LINUX_BCMA_H_ #include -#include +#include #include #include diff --git a/include/linux/bpf_lsm.h b/include/linux/bpf_lsm.h index 143775a27a2a..dda272d78f01 100644 --- a/include/linux/bpf_lsm.h +++ b/include/linux/bpf_lsm.h @@ -14,6 +14,8 @@ #ifdef CONFIG_BPF_LSM +extern bool bpf_lsm_initialized __ro_after_init; + #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ RET bpf_lsm_##NAME(__VA_ARGS__); #include @@ -56,6 +58,8 @@ bool bpf_lsm_hook_returns_errno(u32 btf_id); #else /* !CONFIG_BPF_LSM */ +#define bpf_lsm_initialized false + static inline bool bpf_lsm_is_sleepable_hook(u32 btf_id) { return false; diff --git a/include/linux/cdx/cdx_bus.h b/include/linux/cdx/cdx_bus.h index f54770f110bc..715b026ad95b 100644 --- a/include/linux/cdx/cdx_bus.h +++ b/include/linux/cdx/cdx_bus.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #define MAX_CDX_DEV_RESOURCES 4 diff --git a/include/linux/device-id/acpi.h b/include/linux/device-id/acpi.h new file mode 100644 index 000000000000..65800cefddca --- /dev/null +++ b/include/linux/device-id/acpi.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_ACPI_H +#define LINUX_DEVICE_ID_ACPI_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define ACPI_ID_LEN 16 + +struct acpi_device_id { + __u8 id[ACPI_ID_LEN]; + kernel_ulong_t driver_data; + __u32 cls; + __u32 cls_msk; +}; + +/** + * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with + * the PCI-defined class-code information + * + * @_cls : the class, subclass, prog-if triple for this device + * @_msk : the class mask for this device + * + * This macro is used to create a struct acpi_device_id that matches a + * specific PCI class. The .id and .driver_data fields will be left + * initialized with the default value. + */ +#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (_cls), .cls_msk = (_msk), + +#endif /* ifndef LINUX_DEVICE_ID_ACPI_H */ diff --git a/include/linux/device-id/amba.h b/include/linux/device-id/amba.h new file mode 100644 index 000000000000..114d66a784ac --- /dev/null +++ b/include/linux/device-id/amba.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_AMBA_H +#define LINUX_DEVICE_ID_AMBA_H + +/** + * struct amba_id - identifies a device on an AMBA bus + * @id: The significant bits if the hardware device ID + * @mask: Bitmask specifying which bits of the id field are significant when + * matching. A driver binds to a device when ((hardware device ID) & mask) + * == id. + * @data: Private data used by the driver. + */ +struct amba_id { + unsigned int id; + unsigned int mask; + void *data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_AMBA_H */ diff --git a/include/linux/device-id/ap.h b/include/linux/device-id/ap.h new file mode 100644 index 000000000000..0992333a34db --- /dev/null +++ b/include/linux/device-id/ap.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_AP_H +#define LINUX_DEVICE_ID_AP_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define AP_DEVICE_ID_MATCH_CARD_TYPE 0x01 +#define AP_DEVICE_ID_MATCH_QUEUE_TYPE 0x02 + +/* s390 AP bus devices */ +struct ap_device_id { + __u16 match_flags; /* which fields to match against */ + __u8 dev_type; /* device type */ + kernel_ulong_t driver_info; +}; + +#endif /* ifndef LINUX_DEVICE_ID_AP_H */ diff --git a/include/linux/device-id/apr.h b/include/linux/device-id/apr.h new file mode 100644 index 000000000000..f282608ea018 --- /dev/null +++ b/include/linux/device-id/apr.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_APR_H +#define LINUX_DEVICE_ID_APR_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define APR_NAME_SIZE 32 +#define APR_MODULE_PREFIX "apr:" + +struct apr_device_id { + char name[APR_NAME_SIZE]; + __u32 domain_id; + __u32 svc_id; + __u32 svc_version; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_APR_H */ diff --git a/include/linux/device-id/auxiliary.h b/include/linux/device-id/auxiliary.h new file mode 100644 index 000000000000..9d512dfb23dd --- /dev/null +++ b/include/linux/device-id/auxiliary.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_AUXILIARY_H +#define LINUX_DEVICE_ID_AUXILIARY_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +#define AUXILIARY_NAME_SIZE 40 +#define AUXILIARY_MODULE_PREFIX "auxiliary:" + +struct auxiliary_device_id { + char name[AUXILIARY_NAME_SIZE]; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_AUXILIARY_H */ diff --git a/include/linux/device-id/bcma.h b/include/linux/device-id/bcma.h new file mode 100644 index 000000000000..3e6b973dc4ae --- /dev/null +++ b/include/linux/device-id/bcma.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_BCMA_H +#define LINUX_DEVICE_ID_BCMA_H + +#ifdef __KERNEL__ +#include +#endif + +#define BCMA_CORE(_manuf, _id, _rev, _class) \ + { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, } + +#define BCMA_ANY_MANUF 0xFFFF +#define BCMA_ANY_ID 0xFFFF +#define BCMA_ANY_REV 0xFF +#define BCMA_ANY_CLASS 0xFF + +/* Broadcom's specific AMBA core, see drivers/bcma/ */ +struct bcma_device_id { + __u16 manuf; + __u16 id; + __u8 rev; + __u8 class; +} __attribute__((packed,aligned(2))); + +#endif /* ifndef LINUX_DEVICE_ID_BCMA_H */ diff --git a/include/linux/device-id/ccw.h b/include/linux/device-id/ccw.h new file mode 100644 index 000000000000..6b7086aa5ca8 --- /dev/null +++ b/include/linux/device-id/ccw.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_CCW_H +#define LINUX_DEVICE_ID_CCW_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define CCW_DEVICE_ID_MATCH_CU_TYPE 0x01 +#define CCW_DEVICE_ID_MATCH_CU_MODEL 0x02 +#define CCW_DEVICE_ID_MATCH_DEVICE_TYPE 0x04 +#define CCW_DEVICE_ID_MATCH_DEVICE_MODEL 0x08 + +/* s390 CCW devices */ +struct ccw_device_id { + __u16 match_flags; /* which fields to match against */ + + __u16 cu_type; /* control unit type */ + __u16 dev_type; /* device type */ + __u8 cu_model; /* control unit model */ + __u8 dev_model; /* device model */ + + kernel_ulong_t driver_info; +}; + +#endif /* ifndef LINUX_DEVICE_ID_CCW_H */ diff --git a/include/linux/device-id/cdx.h b/include/linux/device-id/cdx.h new file mode 100644 index 000000000000..c6cb2b5cab5a --- /dev/null +++ b/include/linux/device-id/cdx.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_CDX_H +#define LINUX_DEVICE_ID_CDX_H + +#ifdef __KERNEL__ +#include +#endif + +#define CDX_ANY_ID (0xFFFF) + +enum { + CDX_ID_F_VFIO_DRIVER_OVERRIDE = 1, +}; + +/** + * struct cdx_device_id - CDX device identifier + * @vendor: Vendor ID + * @device: Device ID + * @subvendor: Subsystem vendor ID (or CDX_ANY_ID) + * @subdevice: Subsystem device ID (or CDX_ANY_ID) + * @class: Device class + * Most drivers do not need to specify class/class_mask + * as vendor/device is normally sufficient. + * @class_mask: Limit which sub-fields of the class field are compared. + * @override_only: Match only when dev->driver_override is this driver. + * + * Type of entries in the "device Id" table for CDX devices supported by + * a CDX device driver. + */ +struct cdx_device_id { + __u16 vendor; + __u16 device; + __u16 subvendor; + __u16 subdevice; + __u32 class; + __u32 class_mask; + __u32 override_only; +}; + +#endif /* ifndef LINUX_DEVICE_ID_CDX_H */ diff --git a/include/linux/device-id/coreboot.h b/include/linux/device-id/coreboot.h new file mode 100644 index 000000000000..ff459879781e --- /dev/null +++ b/include/linux/device-id/coreboot.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_COREBOOT_H +#define LINUX_DEVICE_ID_COREBOOT_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/** + * struct coreboot_device_id - Identifies a coreboot table entry + * @tag: tag ID + * @driver_data: driver specific data + */ +struct coreboot_device_id { + __u32 tag; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_COREBOOT_H */ diff --git a/include/linux/device-id/css.h b/include/linux/device-id/css.h new file mode 100644 index 000000000000..67435bb22618 --- /dev/null +++ b/include/linux/device-id/css.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_CSS_H +#define LINUX_DEVICE_ID_CSS_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* s390 css bus devices (subchannels) */ +struct css_device_id { + __u8 match_flags; + __u8 type; /* subchannel type */ + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_CSS_H */ diff --git a/include/linux/device-id/dfl.h b/include/linux/device-id/dfl.h new file mode 100644 index 000000000000..bd0c9dbafeeb --- /dev/null +++ b/include/linux/device-id/dfl.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_DFL_H +#define LINUX_DEVICE_ID_DFL_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* + * DFL (Device Feature List) + * + * DFL defines a linked list of feature headers within the device MMIO space to + * provide an extensible way of adding features. Software can walk through these + * predefined data structures to enumerate features. It is now used in the FPGA. + * See Documentation/fpga/dfl.rst for more information. + * + * The dfl bus type is introduced to match the individual feature devices (dfl + * devices) for specific dfl drivers. + */ + +/** + * struct dfl_device_id - dfl device identifier + * @type: DFL FIU type of the device. See enum dfl_id_type. + * @feature_id: feature identifier local to its DFL FIU type. + * @driver_data: driver specific data. + */ +struct dfl_device_id { + __u16 type; + __u16 feature_id; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_DFL_H */ diff --git a/include/linux/device-id/dmi.h b/include/linux/device-id/dmi.h new file mode 100644 index 000000000000..fdc4adbad133 --- /dev/null +++ b/include/linux/device-id/dmi.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_DMI_H +#define LINUX_DEVICE_ID_DMI_H + +#define DMI_MATCH(a, b) { .slot = a, .substr = b } +#define DMI_EXACT_MATCH(a, b) { .slot = a, .substr = b, .exact_match = 1 } + +/* dmi */ +enum dmi_field { + DMI_NONE, + DMI_BIOS_VENDOR, + DMI_BIOS_VERSION, + DMI_BIOS_DATE, + DMI_BIOS_RELEASE, + DMI_EC_FIRMWARE_RELEASE, + DMI_SYS_VENDOR, + DMI_PRODUCT_NAME, + DMI_PRODUCT_VERSION, + DMI_PRODUCT_SERIAL, + DMI_PRODUCT_UUID, + DMI_PRODUCT_SKU, + DMI_PRODUCT_FAMILY, + DMI_BOARD_VENDOR, + DMI_BOARD_NAME, + DMI_BOARD_VERSION, + DMI_BOARD_SERIAL, + DMI_BOARD_ASSET_TAG, + DMI_CHASSIS_VENDOR, + DMI_CHASSIS_TYPE, + DMI_CHASSIS_VERSION, + DMI_CHASSIS_SERIAL, + DMI_CHASSIS_ASSET_TAG, + DMI_STRING_MAX, + DMI_OEM_STRING, /* special case - will not be in dmi_ident */ +}; + +struct dmi_strmatch { + unsigned char slot:7; + unsigned char exact_match:1; + char substr[79]; +}; + +struct dmi_system_id { + int (*callback)(const struct dmi_system_id *); + const char *ident; + struct dmi_strmatch matches[4]; + void *driver_data; +}; + +/* + * struct dmi_device_id appears during expansion of + * "MODULE_DEVICE_TABLE(dmi, x)". Compiler doesn't look inside it + * but this is enough for gcc 3.4.6 to error out: + * error: storage size of '__mod_dmi_device_table' isn't known + */ +#define dmi_device_id dmi_system_id + +#endif /* ifndef LINUX_DEVICE_ID_DMI_H */ diff --git a/include/linux/device-id/eisa.h b/include/linux/device-id/eisa.h new file mode 100644 index 000000000000..1eeae6247524 --- /dev/null +++ b/include/linux/device-id/eisa.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_EISA_H +#define LINUX_DEVICE_ID_EISA_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +/* EISA */ + +#define EISA_SIG_LEN 8 + +/* The EISA signature, in ASCII form, null terminated */ +struct eisa_device_id { + char sig[EISA_SIG_LEN]; + kernel_ulong_t driver_data; +}; + +#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s" + +#endif /* ifndef LINUX_DEVICE_ID_EISA_H */ diff --git a/include/linux/device-id/fsl_mc.h b/include/linux/device-id/fsl_mc.h new file mode 100644 index 000000000000..0cfa94923670 --- /dev/null +++ b/include/linux/device-id/fsl_mc.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_FSL_MC_H +#define LINUX_DEVICE_ID_FSL_MC_H + +#ifdef __KERNEL__ +#include +#endif + +/** + * struct fsl_mc_device_id - MC object device identifier + * @vendor: vendor ID + * @obj_type: MC object type + * + * Type of entries in the "device Id" table for MC object devices supported by + * a MC object device driver. The last entry of the table has vendor set to 0x0 + */ +struct fsl_mc_device_id { + __u16 vendor; + const char obj_type[16]; +}; + +#endif /* ifndef LINUX_DEVICE_ID_FSL_MC_H */ diff --git a/include/linux/device-id/hda.h b/include/linux/device-id/hda.h new file mode 100644 index 000000000000..42542580f955 --- /dev/null +++ b/include/linux/device-id/hda.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_HDA_H +#define LINUX_DEVICE_ID_HDA_H + +#ifdef __KERNEL__ +#include +#endif + +struct hda_device_id { + __u32 vendor_id; + __u32 rev_id; + __u8 api_version; + const char *name; + unsigned long driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_HDA_H */ diff --git a/include/linux/device-id/hid.h b/include/linux/device-id/hid.h new file mode 100644 index 000000000000..e865fc64bf94 --- /dev/null +++ b/include/linux/device-id/hid.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_HID_H +#define LINUX_DEVICE_ID_HID_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define HID_ANY_ID (~0) +#define HID_BUS_ANY 0xffff +#define HID_GROUP_ANY 0x0000 + +struct hid_device_id { + __u16 bus; + __u16 group; + __u32 vendor; + __u32 product; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_HID_H */ diff --git a/include/linux/device-id/hv_vmbus.h b/include/linux/device-id/hv_vmbus.h new file mode 100644 index 000000000000..a7682c05619f --- /dev/null +++ b/include/linux/device-id/hv_vmbus.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_HV_VMBUS_H +#define LINUX_DEVICE_ID_HV_VMBUS_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* + * For Hyper-V devices we use the device guid as the id. + */ +struct hv_vmbus_device_id { + guid_t guid; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_HV_VMBUS_H */ diff --git a/include/linux/device-id/i2c.h b/include/linux/device-id/i2c.h new file mode 100644 index 000000000000..21f9b581e7a9 --- /dev/null +++ b/include/linux/device-id/i2c.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_I2C_H +#define LINUX_DEVICE_ID_I2C_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +/* i2c */ + +#define I2C_NAME_SIZE 20 +#define I2C_MODULE_PREFIX "i2c:" + +struct i2c_device_id { + char name[I2C_NAME_SIZE]; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_I2C_H */ diff --git a/include/linux/device-id/i3c.h b/include/linux/device-id/i3c.h new file mode 100644 index 000000000000..5d8222c9f908 --- /dev/null +++ b/include/linux/device-id/i3c.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_I3C_H +#define LINUX_DEVICE_ID_I3C_H + +#ifdef __KERNEL__ +#include +#endif + +/* i3c */ + +#define I3C_MATCH_DCR 0x1 +#define I3C_MATCH_MANUF 0x2 +#define I3C_MATCH_PART 0x4 +#define I3C_MATCH_EXTRA_INFO 0x8 + +struct i3c_device_id { + __u8 match_flags; + __u8 dcr; + __u16 manuf_id; + __u16 part_id; + __u16 extra_info; + + const void *data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_I3C_H */ diff --git a/include/linux/device-id/ieee1394.h b/include/linux/device-id/ieee1394.h new file mode 100644 index 000000000000..63023964724a --- /dev/null +++ b/include/linux/device-id/ieee1394.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_IEEE1394_H +#define LINUX_DEVICE_ID_IEEE1394_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define IEEE1394_MATCH_VENDOR_ID 0x0001 +#define IEEE1394_MATCH_MODEL_ID 0x0002 +#define IEEE1394_MATCH_SPECIFIER_ID 0x0004 +#define IEEE1394_MATCH_VERSION 0x0008 + +struct ieee1394_device_id { + __u32 match_flags; + __u32 vendor_id; + __u32 model_id; + __u32 specifier_id; + __u32 version; + union { + kernel_ulong_t driver_data; + const void *driver_data_ptr; + }; +}; + +#endif /* ifndef LINUX_DEVICE_ID_IEEE1394_H */ diff --git a/include/linux/device-id/input.h b/include/linux/device-id/input.h new file mode 100644 index 000000000000..66d7e78d32c0 --- /dev/null +++ b/include/linux/device-id/input.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_INPUT_H +#define LINUX_DEVICE_ID_INPUT_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* Input */ +#define INPUT_DEVICE_ID_EV_MAX 0x1f +#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71 +#define INPUT_DEVICE_ID_KEY_MAX 0x2ff +#define INPUT_DEVICE_ID_REL_MAX 0x0f +#define INPUT_DEVICE_ID_ABS_MAX 0x3f +#define INPUT_DEVICE_ID_MSC_MAX 0x07 +#define INPUT_DEVICE_ID_LED_MAX 0x0f +#define INPUT_DEVICE_ID_SND_MAX 0x07 +#define INPUT_DEVICE_ID_FF_MAX 0x7f +#define INPUT_DEVICE_ID_SW_MAX 0x11 +#define INPUT_DEVICE_ID_PROP_MAX 0x1f + +#define INPUT_DEVICE_ID_MATCH_BUS 1 +#define INPUT_DEVICE_ID_MATCH_VENDOR 2 +#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 +#define INPUT_DEVICE_ID_MATCH_VERSION 8 + +#define INPUT_DEVICE_ID_MATCH_EVBIT 0x0010 +#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x0020 +#define INPUT_DEVICE_ID_MATCH_RELBIT 0x0040 +#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x0080 +#define INPUT_DEVICE_ID_MATCH_MSCIT 0x0100 +#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x0200 +#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x0400 +#define INPUT_DEVICE_ID_MATCH_FFBIT 0x0800 +#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000 +#define INPUT_DEVICE_ID_MATCH_PROPBIT 0x2000 + +struct input_device_id { + + kernel_ulong_t flags; + + __u16 bustype; + __u16 vendor; + __u16 product; + __u16 version; + + kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1]; + kernel_ulong_t propbit[INPUT_DEVICE_ID_PROP_MAX / BITS_PER_LONG + 1]; + + kernel_ulong_t driver_info; +}; + +#endif /* ifndef LINUX_DEVICE_ID_INPUT_H */ diff --git a/include/linux/device-id/ipack.h b/include/linux/device-id/ipack.h new file mode 100644 index 000000000000..7f9b425e1e30 --- /dev/null +++ b/include/linux/device-id/ipack.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_IPACK_H +#define LINUX_DEVICE_ID_IPACK_H + +#ifdef __KERNEL__ +#include +#endif + +#define IPACK_ANY_FORMAT 0xff +#define IPACK_ANY_ID (~0) +struct ipack_device_id { + __u8 format; /* Format version or IPACK_ANY_ID */ + __u32 vendor; /* Vendor ID or IPACK_ANY_ID */ + __u32 device; /* Device ID or IPACK_ANY_ID */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_IPACK_H */ diff --git a/include/linux/device-id/isapnp.h b/include/linux/device-id/isapnp.h new file mode 100644 index 000000000000..ba659c32650a --- /dev/null +++ b/include/linux/device-id/isapnp.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_ISAPNP_H +#define LINUX_DEVICE_ID_ISAPNP_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +#define ISAPNP_ANY_ID 0xffff +struct isapnp_device_id { + unsigned short card_vendor, card_device; + unsigned short vendor, function; + kernel_ulong_t driver_data; /* data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_ISAPNP_H */ diff --git a/include/linux/device-id/ishtp.h b/include/linux/device-id/ishtp.h new file mode 100644 index 000000000000..c66f144b4cb6 --- /dev/null +++ b/include/linux/device-id/ishtp.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_ISHTP_H +#define LINUX_DEVICE_ID_ISHTP_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* ISHTP (Integrated Sensor Hub Transport Protocol) */ + +#define ISHTP_MODULE_PREFIX "ishtp:" + +/** + * struct ishtp_device_id - ISHTP device identifier + * @guid: GUID of the device. + * @driver_data: pointer to driver specific data + */ +struct ishtp_device_id { + guid_t guid; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_ISHTP_H */ diff --git a/include/linux/device-id/mcb.h b/include/linux/device-id/mcb.h new file mode 100644 index 000000000000..a5daec32c21c --- /dev/null +++ b/include/linux/device-id/mcb.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_MCB_H +#define LINUX_DEVICE_ID_MCB_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +struct mcb_device_id { + __u16 device; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_MCB_H */ diff --git a/include/linux/device-id/mdio.h b/include/linux/device-id/mdio.h new file mode 100644 index 000000000000..e6cda2d91ddb --- /dev/null +++ b/include/linux/device-id/mdio.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_MDIO_H +#define LINUX_DEVICE_ID_MDIO_H + +#ifdef __KERNEL__ +#include +#endif + +#define MDIO_MODULE_PREFIX "mdio:" + +#define MDIO_ID_FMT "%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u" +#define MDIO_ID_ARGS(_id) \ + ((_id)>>31) & 1, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \ + ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \ + ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \ + ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \ + ((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \ + ((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \ + ((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \ + ((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1 + +/** + * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus + * @phy_id: The result of + * (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&MII_PHYSID2)) & @phy_id_mask + * for this PHY type + * @phy_id_mask: Defines the significant bits of @phy_id. A value of 0 + * is used to terminate an array of struct mdio_device_id. + */ +struct mdio_device_id { + __u32 phy_id; + __u32 phy_id_mask; +}; + +#endif /* ifndef LINUX_DEVICE_ID_MDIO_H */ diff --git a/include/linux/device-id/mei_cl.h b/include/linux/device-id/mei_cl.h new file mode 100644 index 000000000000..aeeb95da4b29 --- /dev/null +++ b/include/linux/device-id/mei_cl.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_MEI_CL_H +#define LINUX_DEVICE_ID_MEI_CL_H + +#ifdef __KERNEL__ +#include +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define MEI_CL_MODULE_PREFIX "mei:" +#define MEI_CL_NAME_SIZE 32 +#define MEI_CL_VERSION_ANY 0xff + +/** + * struct mei_cl_device_id - MEI client device identifier + * @name: helper name + * @uuid: client uuid + * @version: client protocol version + * @driver_info: information used by the driver. + * + * identifies mei client device by uuid and name + */ +struct mei_cl_device_id { + char name[MEI_CL_NAME_SIZE]; + uuid_le uuid; + __u8 version; + kernel_ulong_t driver_info; +}; + +#endif /* ifndef LINUX_DEVICE_ID_MEI_CL_H */ diff --git a/include/linux/device-id/mhi.h b/include/linux/device-id/mhi.h new file mode 100644 index 000000000000..30a27a71a57f --- /dev/null +++ b/include/linux/device-id/mhi.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_MHI_H +#define LINUX_DEVICE_ID_MHI_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +#define MHI_DEVICE_MODALIAS_FMT "mhi:%s" +#define MHI_NAME_SIZE 32 + +#define MHI_EP_DEVICE_MODALIAS_FMT "mhi_ep:%s" + +/** + * struct mhi_device_id - MHI device identification + * @chan: MHI channel name + * @driver_data: driver data; + */ +struct mhi_device_id { + const char chan[MHI_NAME_SIZE]; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_MHI_H */ diff --git a/include/linux/device-id/mips_cdmm.h b/include/linux/device-id/mips_cdmm.h new file mode 100644 index 000000000000..e1623884103a --- /dev/null +++ b/include/linux/device-id/mips_cdmm.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_MIPS_CDMM_H +#define LINUX_DEVICE_ID_MIPS_CDMM_H + +#ifdef __KERNEL__ +#include +#endif + +/** + * struct mips_cdmm_device_id - identifies devices in MIPS CDMM bus + * @type: Device type identifier. + */ +struct mips_cdmm_device_id { + __u8 type; +}; + +#endif /* ifndef LINUX_DEVICE_ID_MIPS_CDMM_H */ diff --git a/include/linux/device-id/of.h b/include/linux/device-id/of.h new file mode 100644 index 000000000000..28ea360f8f9a --- /dev/null +++ b/include/linux/device-id/of.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_OF_H +#define LINUX_DEVICE_ID_OF_H + +/* + * Struct used for matching a device + */ +struct of_device_id { + char name[32]; + char type[32]; + char compatible[128]; + const void *data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_OF_H */ diff --git a/include/linux/device-id/parisc.h b/include/linux/device-id/parisc.h new file mode 100644 index 000000000000..2974eb26a8be --- /dev/null +++ b/include/linux/device-id/parisc.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_PARISC_H +#define LINUX_DEVICE_ID_PARISC_H + +#ifdef __KERNEL__ +#include +#endif + +#define PA_HWTYPE_ANY_ID 0xff +#define PA_HVERSION_REV_ANY_ID 0xff +#define PA_HVERSION_ANY_ID 0xffff +#define PA_SVERSION_ANY_ID 0xffffffff + +struct parisc_device_id { + __u8 hw_type; /* 5 bits used */ + __u8 hversion_rev; /* 4 bits */ + __u16 hversion; /* 12 bits */ + __u32 sversion; /* 20 bits */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_PARISC_H */ diff --git a/include/linux/device-id/pci.h b/include/linux/device-id/pci.h new file mode 100644 index 000000000000..4a635d531cd6 --- /dev/null +++ b/include/linux/device-id/pci.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_PCI_H +#define LINUX_DEVICE_ID_PCI_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define PCI_ANY_ID (~0) + +enum { + PCI_ID_F_VFIO_DRIVER_OVERRIDE = 1, +}; + +/** + * struct pci_device_id - PCI device ID structure + * @vendor: Vendor ID to match (or PCI_ANY_ID) + * @device: Device ID to match (or PCI_ANY_ID) + * @subvendor: Subsystem vendor ID to match (or PCI_ANY_ID) + * @subdevice: Subsystem device ID to match (or PCI_ANY_ID) + * @class: Device class, subclass, and "interface" to match. + * See Appendix D of the PCI Local Bus Spec or + * include/linux/pci_ids.h for a full list of classes. + * Most drivers do not need to specify class/class_mask + * as vendor/device is normally sufficient. + * @class_mask: Limit which sub-fields of the class field are compared. + * See drivers/scsi/sym53c8xx_2/ for example of usage. + * @driver_data: Data private to the driver. + * Most drivers don't need to use driver_data field. + * Best practice is to use driver_data as an index + * into a static list of equivalent device types, + * instead of using it as a pointer. + * @override_only: Match only when dev->driver_override is this driver. + */ +struct pci_device_id { + __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ + __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ + __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ + kernel_ulong_t driver_data; /* Data private to the driver */ + __u32 override_only; +}; + +/* pci_epf */ + +#define PCI_EPF_NAME_SIZE 20 +#define PCI_EPF_MODULE_PREFIX "pci_epf:" + +struct pci_epf_device_id { + char name[PCI_EPF_NAME_SIZE]; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_PCI_H */ diff --git a/include/linux/device-id/pcmcia.h b/include/linux/device-id/pcmcia.h new file mode 100644 index 000000000000..c0d809be2338 --- /dev/null +++ b/include/linux/device-id/pcmcia.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_PCMCIA_H +#define LINUX_DEVICE_ID_PCMCIA_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* PCMCIA */ + +#define PCMCIA_DEV_ID_MATCH_MANF_ID 0x0001 +#define PCMCIA_DEV_ID_MATCH_CARD_ID 0x0002 +#define PCMCIA_DEV_ID_MATCH_FUNC_ID 0x0004 +#define PCMCIA_DEV_ID_MATCH_FUNCTION 0x0008 +#define PCMCIA_DEV_ID_MATCH_PROD_ID1 0x0010 +#define PCMCIA_DEV_ID_MATCH_PROD_ID2 0x0020 +#define PCMCIA_DEV_ID_MATCH_PROD_ID3 0x0040 +#define PCMCIA_DEV_ID_MATCH_PROD_ID4 0x0080 +#define PCMCIA_DEV_ID_MATCH_DEVICE_NO 0x0100 +#define PCMCIA_DEV_ID_MATCH_FAKE_CIS 0x0200 +#define PCMCIA_DEV_ID_MATCH_ANONYMOUS 0x0400 + +struct pcmcia_device_id { + __u16 match_flags; + + __u16 manf_id; + __u16 card_id; + + __u8 func_id; + + /* for real multi-function devices */ + __u8 function; + + /* for pseudo multi-function devices */ + __u8 device_no; + + __u32 prod_id_hash[4]; + + /* not matched against in kernelspace */ + const char * prod_id[4]; + + /* not matched against */ + kernel_ulong_t driver_info; + char * cisfile; +}; + +#endif /* ifndef LINUX_DEVICE_ID_PCMCIA_H */ diff --git a/include/linux/device-id/platform.h b/include/linux/device-id/platform.h new file mode 100644 index 000000000000..d6beeb4a2574 --- /dev/null +++ b/include/linux/device-id/platform.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_PLATFORM_H +#define LINUX_DEVICE_ID_PLATFORM_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +#define PLATFORM_NAME_SIZE 24 +#define PLATFORM_MODULE_PREFIX "platform:" + +struct platform_device_id { + char name[PLATFORM_NAME_SIZE]; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_PLATFORM_H */ diff --git a/include/linux/device-id/pnp.h b/include/linux/device-id/pnp.h new file mode 100644 index 000000000000..325f17216df8 --- /dev/null +++ b/include/linux/device-id/pnp.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_PNP_H +#define LINUX_DEVICE_ID_PNP_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define PNP_ID_LEN 8 +#define PNP_MAX_DEVICES 8 + +struct pnp_device_id { + __u8 id[PNP_ID_LEN]; + kernel_ulong_t driver_data; +}; + +struct pnp_card_device_id { + __u8 id[PNP_ID_LEN]; + kernel_ulong_t driver_data; + struct { + __u8 id[PNP_ID_LEN]; + } devs[PNP_MAX_DEVICES]; +}; + +#endif /* ifndef LINUX_DEVICE_ID_PNP_H */ diff --git a/include/linux/device-id/rio.h b/include/linux/device-id/rio.h new file mode 100644 index 000000000000..31addf69ad1f --- /dev/null +++ b/include/linux/device-id/rio.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_RIO_H +#define LINUX_DEVICE_ID_RIO_H + +#ifdef __KERNEL__ +#include +#endif + +/* RapidIO */ + +#define RIO_ANY_ID 0xffff + +/** + * struct rio_device_id - RIO device identifier + * @did: RapidIO device ID + * @vid: RapidIO vendor ID + * @asm_did: RapidIO assembly device ID + * @asm_vid: RapidIO assembly vendor ID + * + * Identifies a RapidIO device based on both the device/vendor IDs and + * the assembly device/vendor IDs. + */ +struct rio_device_id { + __u16 did, vid; + __u16 asm_did, asm_vid; +}; + +#endif /* ifndef LINUX_DEVICE_ID_RIO_H */ diff --git a/include/linux/device-id/rpmsg.h b/include/linux/device-id/rpmsg.h new file mode 100644 index 000000000000..dd53e7b7dc4f --- /dev/null +++ b/include/linux/device-id/rpmsg.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_RPMSG_H +#define LINUX_DEVICE_ID_RPMSG_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +/* rpmsg */ + +#define RPMSG_NAME_SIZE 32 +#define RPMSG_DEVICE_MODALIAS_FMT "rpmsg:%s" + +struct rpmsg_device_id { + char name[RPMSG_NAME_SIZE]; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_RPMSG_H */ diff --git a/include/linux/device-id/sdio.h b/include/linux/device-id/sdio.h new file mode 100644 index 000000000000..609d60a10cd3 --- /dev/null +++ b/include/linux/device-id/sdio.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SDIO_H +#define LINUX_DEVICE_ID_SDIO_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* SDIO */ + +#define SDIO_ANY_ID (~0) + +struct sdio_device_id { + __u8 class; /* Standard interface or SDIO_ANY_ID */ + __u16 vendor; /* Vendor or SDIO_ANY_ID */ + __u16 device; /* Device ID or SDIO_ANY_ID */ + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_SDIO_H */ diff --git a/include/linux/device-id/sdw.h b/include/linux/device-id/sdw.h new file mode 100644 index 000000000000..dbed7fde1ace --- /dev/null +++ b/include/linux/device-id/sdw.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SDW_H +#define LINUX_DEVICE_ID_SDW_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +struct sdw_device_id { + __u16 mfg_id; + __u16 part_id; + __u8 sdw_version; + __u8 class_id; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_SDW_H */ diff --git a/include/linux/device-id/serio.h b/include/linux/device-id/serio.h new file mode 100644 index 000000000000..b4c02adf220c --- /dev/null +++ b/include/linux/device-id/serio.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SERIO_H +#define LINUX_DEVICE_ID_SERIO_H + +#ifdef __KERNEL__ +#include +#endif + +#define SERIO_ANY 0xff + +struct serio_device_id { + __u8 type; + __u8 extra; + __u8 id; + __u8 proto; +}; + +#endif /* ifndef LINUX_DEVICE_ID_SERIO_H */ diff --git a/include/linux/device-id/slim.h b/include/linux/device-id/slim.h new file mode 100644 index 000000000000..54f8abe09e18 --- /dev/null +++ b/include/linux/device-id/slim.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SLIM_H +#define LINUX_DEVICE_ID_SLIM_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* SLIMbus */ + +#define SLIMBUS_NAME_SIZE 32 +#define SLIMBUS_MODULE_PREFIX "slim:" + +struct slim_device_id { + __u16 manf_id, prod_code; + __u16 dev_index, instance; + + /* Data private to the driver */ + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_SLIM_H */ diff --git a/include/linux/device-id/spi.h b/include/linux/device-id/spi.h new file mode 100644 index 000000000000..7a77d0d6672b --- /dev/null +++ b/include/linux/device-id/spi.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SPI_H +#define LINUX_DEVICE_ID_SPI_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +/* spi */ + +#define SPI_NAME_SIZE 32 +#define SPI_MODULE_PREFIX "spi:" + +struct spi_device_id { + char name[SPI_NAME_SIZE]; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_SPI_H */ diff --git a/include/linux/device-id/spmi.h b/include/linux/device-id/spmi.h new file mode 100644 index 000000000000..a821c42cfc9a --- /dev/null +++ b/include/linux/device-id/spmi.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SPMI_H +#define LINUX_DEVICE_ID_SPMI_H + +#ifdef __KERNEL__ +typedef unsigned long kernel_ulong_t; +#endif + +#define SPMI_NAME_SIZE 32 +#define SPMI_MODULE_PREFIX "spmi:" + +struct spmi_device_id { + char name[SPMI_NAME_SIZE]; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_SPMI_H */ diff --git a/include/linux/device-id/ssam.h b/include/linux/device-id/ssam.h new file mode 100644 index 000000000000..550cca115a55 --- /dev/null +++ b/include/linux/device-id/ssam.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SSAM_H +#define LINUX_DEVICE_ID_SSAM_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* Surface System Aggregator Module */ + +#define SSAM_MATCH_TARGET 0x1 +#define SSAM_MATCH_INSTANCE 0x2 +#define SSAM_MATCH_FUNCTION 0x4 + +struct ssam_device_id { + __u8 match_flags; + + __u8 domain; + __u8 category; + __u8 target; + __u8 instance; + __u8 function; + + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_SSAM_H */ diff --git a/include/linux/device-id/ssb.h b/include/linux/device-id/ssb.h new file mode 100644 index 000000000000..678d40828299 --- /dev/null +++ b/include/linux/device-id/ssb.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_SSB_H +#define LINUX_DEVICE_ID_SSB_H + +#ifdef __KERNEL__ +#include +#endif + +#define SSB_ANY_VENDOR 0xFFFF +#define SSB_ANY_ID 0xFFFF +#define SSB_ANY_REV 0xFF + +/* SSB core, see drivers/ssb/ */ +struct ssb_device_id { + __u16 vendor; + __u16 coreid; + __u8 revision; + __u8 __pad; +} __attribute__((packed, aligned(2))); + +#define SSB_DEVICE(_vendor, _coreid, _revision) \ + { .vendor = _vendor, .coreid = _coreid, .revision = _revision } + +#endif /* ifndef LINUX_DEVICE_ID_SSB_H */ diff --git a/include/linux/device-id/tb.h b/include/linux/device-id/tb.h new file mode 100644 index 000000000000..4c62edff8bb7 --- /dev/null +++ b/include/linux/device-id/tb.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_TB_H +#define LINUX_DEVICE_ID_TB_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define TBSVC_MATCH_PROTOCOL_KEY 0x0001 +#define TBSVC_MATCH_PROTOCOL_ID 0x0002 +#define TBSVC_MATCH_PROTOCOL_VERSION 0x0004 +#define TBSVC_MATCH_PROTOCOL_REVISION 0x0008 + +/** + * struct tb_service_id - Thunderbolt service identifiers + * @match_flags: Flags used to match the structure + * @protocol_key: Protocol key the service supports + * @protocol_id: Protocol id the service supports + * @protocol_version: Version of the protocol + * @protocol_revision: Revision of the protocol software + * @driver_data: Driver specific data + * + * Thunderbolt XDomain services are exposed as devices where each device + * carries the protocol information the service supports. Thunderbolt + * XDomain service drivers match against that information. + */ +struct tb_service_id { + __u32 match_flags; + char protocol_key[8 + 1]; + __u32 protocol_id; + __u32 protocol_version; + __u32 protocol_revision; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_TB_H */ diff --git a/include/linux/device-id/tee_client.h b/include/linux/device-id/tee_client.h new file mode 100644 index 000000000000..ed81f4228185 --- /dev/null +++ b/include/linux/device-id/tee_client.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_TEE_CLIENT_H +#define LINUX_DEVICE_ID_TEE_CLIENT_H + +#ifdef __KERNEL__ +#include +#endif + +/** + * struct tee_client_device_id - tee based device identifier + * @uuid: For TEE based client devices we use the device uuid as + * the identifier. + */ +struct tee_client_device_id { + uuid_t uuid; +}; + +#endif /* ifndef LINUX_DEVICE_ID_TEE_CLIENT_H */ diff --git a/include/linux/device-id/typec.h b/include/linux/device-id/typec.h new file mode 100644 index 000000000000..dc234733408b --- /dev/null +++ b/include/linux/device-id/typec.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_TYPEC_H +#define LINUX_DEVICE_ID_TYPEC_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* USB Type-C Alternate Modes */ + +#define TYPEC_ANY_MODE 0x7 + +/** + * struct typec_device_id - USB Type-C alternate mode identifiers + * @svid: Standard or Vendor ID + * @mode: Mode index + * @driver_data: Driver specific data + */ +struct typec_device_id { + __u16 svid; + __u8 mode; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_TYPEC_H */ diff --git a/include/linux/device-id/ulpi.h b/include/linux/device-id/ulpi.h new file mode 100644 index 000000000000..b5105b4cfacc --- /dev/null +++ b/include/linux/device-id/ulpi.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_ULPI_H +#define LINUX_DEVICE_ID_ULPI_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +struct ulpi_device_id { + __u16 vendor; + __u16 product; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_ULPI_H */ diff --git a/include/linux/device-id/usb.h b/include/linux/device-id/usb.h new file mode 100644 index 000000000000..a7ce5f6e1106 --- /dev/null +++ b/include/linux/device-id/usb.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_USB_H +#define LINUX_DEVICE_ID_USB_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* + * Device table entry for "new style" table-driven USB drivers. + * User mode code can read these tables to choose which modules to load. + * Declare the table as a MODULE_DEVICE_TABLE. + * + * A probe() parameter will point to a matching entry from this table. + * Use the driver_info field for each match to hold information tied + * to that match: device quirks, etc. + * + * Terminate the driver's table with an all-zeroes entry. + * Use the flag values to control which fields are compared. + */ + +/** + * struct usb_device_id - identifies USB devices for probing and hotplugging + * @match_flags: Bit mask controlling which of the other fields are used to + * match against new devices. Any field except for driver_info may be + * used, although some only make sense in conjunction with other fields. + * This is usually set by a USB_DEVICE_*() macro, which sets all + * other fields in this structure except for driver_info. + * @idVendor: USB vendor ID for a device; numbers are assigned + * by the USB forum to its members. + * @idProduct: Vendor-assigned product ID. + * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers. + * This is also used to identify individual product versions, for + * a range consisting of a single device. + * @bcdDevice_hi: High end of version number range. The range of product + * versions is inclusive. + * @bDeviceClass: Class of device; numbers are assigned + * by the USB forum. Products may choose to implement classes, + * or be vendor-specific. Device classes specify behavior of all + * the interfaces on a device. + * @bDeviceSubClass: Subclass of device; associated with bDeviceClass. + * @bDeviceProtocol: Protocol of device; associated with bDeviceClass. + * @bInterfaceClass: Class of interface; numbers are assigned + * by the USB forum. Products may choose to implement classes, + * or be vendor-specific. Interface classes specify behavior only + * of a given interface; other interfaces may support other classes. + * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass. + * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass. + * @bInterfaceNumber: Number of interface; composite devices may use + * fixed interface numbers to differentiate between vendor-specific + * interfaces. + * @driver_info: Holds information used by the driver. Usually it holds + * a pointer to a descriptor understood by the driver, or perhaps + * device flags. + * + * In most cases, drivers will create a table of device IDs by using + * USB_DEVICE(), or similar macros designed for that purpose. + * They will then export it to userspace using MODULE_DEVICE_TABLE(), + * and provide it to the USB core through their usb_driver structure. + * + * See the usb_match_id() function for information about how matches are + * performed. Briefly, you will normally use one of several macros to help + * construct these entries. Each entry you provide will either identify + * one or more specific products, or will identify a class of products + * which have agreed to behave the same. You should put the more specific + * matches towards the beginning of your table, so that driver_info can + * record quirks of specific products. + */ +struct usb_device_id { + /* which fields to match against? */ + __u16 match_flags; + + /* Used for product specific matches; range is inclusive */ + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice_lo; + __u16 bcdDevice_hi; + + /* Used for device class matches */ + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + + /* Used for interface class matches */ + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + + /* Used for vendor-specific interface matches */ + __u8 bInterfaceNumber; + + /* not matched against */ + kernel_ulong_t driver_info + __attribute__((aligned(sizeof(kernel_ulong_t)))); +}; + +/* Some useful macros to use to create struct usb_device_id */ +#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 +#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 +#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 +#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 +#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 +#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 +#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 +#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 +#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 +#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 +#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400 + +#endif /* ifndef LINUX_DEVICE_ID_USB_H */ diff --git a/include/linux/device-id/vchiq.h b/include/linux/device-id/vchiq.h new file mode 100644 index 000000000000..16b1b874c02d --- /dev/null +++ b/include/linux/device-id/vchiq.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_VCHIQ_H +#define LINUX_DEVICE_ID_VCHIQ_H + +struct vchiq_device_id { + char name[32]; +}; + +#endif /* ifndef LINUX_DEVICE_ID_VCHIQ_H */ diff --git a/include/linux/device-id/vio.h b/include/linux/device-id/vio.h new file mode 100644 index 000000000000..8ed7ea9cec07 --- /dev/null +++ b/include/linux/device-id/vio.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_VIO_H +#define LINUX_DEVICE_ID_VIO_H + +/* VIO */ +struct vio_device_id { + char type[32]; + char compat[32]; +}; + +#endif /* ifndef LINUX_DEVICE_ID_VIO_H */ diff --git a/include/linux/device-id/virtio.h b/include/linux/device-id/virtio.h new file mode 100644 index 000000000000..9648a42d4f26 --- /dev/null +++ b/include/linux/device-id/virtio.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_VIRTIO_H +#define LINUX_DEVICE_ID_VIRTIO_H + +#ifdef __KERNEL__ +#include +#endif + +#define VIRTIO_DEV_ANY_ID 0xffffffff + +struct virtio_device_id { + __u32 device; + __u32 vendor; +}; + +#endif /* ifndef LINUX_DEVICE_ID_VIRTIO_H */ diff --git a/include/linux/device-id/wmi.h b/include/linux/device-id/wmi.h new file mode 100644 index 000000000000..9f55c83c5203 --- /dev/null +++ b/include/linux/device-id/wmi.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_WMI_H +#define LINUX_DEVICE_ID_WMI_H + +/* WMI */ + +#define WMI_MODULE_PREFIX "wmi:" + +/** + * struct wmi_device_id - WMI device identifier + * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba + * @context: pointer to driver specific data + */ +struct wmi_device_id { + const char guid_string[UUID_STRING_LEN+1]; + const void *context; +}; + +#endif /* ifndef LINUX_DEVICE_ID_WMI_H */ diff --git a/include/linux/device-id/x86_cpu.h b/include/linux/device-id/x86_cpu.h new file mode 100644 index 000000000000..f44e5253ccca --- /dev/null +++ b/include/linux/device-id/x86_cpu.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_X86_CPU_H +#define LINUX_DEVICE_ID_X86_CPU_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +/* Wild cards for x86_cpu_id::vendor, family, model and feature */ +#define X86_VENDOR_ANY 0xffff +#define X86_FAMILY_ANY 0 +#define X86_MODEL_ANY 0 +#define X86_STEPPING_ANY 0 +#define X86_STEP_MIN 0 +#define X86_STEP_MAX 0xf +#define X86_PLATFORM_ANY 0x0 +#define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ +#define X86_CPU_TYPE_ANY 0 + +/* + * Match x86 CPUs for CPU specific drivers. + * See documentation of "x86_match_cpu" for details. + */ + +/* + * MODULE_DEVICE_TABLE expects this struct to be called x86cpu_device_id. + * Although gcc seems to ignore this error, clang fails without this define. + */ +#define x86cpu_device_id x86_cpu_id +struct x86_cpu_id { + __u16 vendor; + __u16 family; + __u16 model; + __u16 steppings; + __u16 feature; /* bit index */ + /* Solely for kernel-internal use: DO NOT EXPORT to userspace! */ + __u16 flags; + __u8 platform_mask; + __u8 type; + kernel_ulong_t driver_data; +}; + +#endif /* ifndef LINUX_DEVICE_ID_X86_CPU_H */ diff --git a/include/linux/device-id/zorro.h b/include/linux/device-id/zorro.h new file mode 100644 index 000000000000..5fdac8168983 --- /dev/null +++ b/include/linux/device-id/zorro.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef LINUX_DEVICE_ID_ZORRO_H +#define LINUX_DEVICE_ID_ZORRO_H + +#ifdef __KERNEL__ +#include +typedef unsigned long kernel_ulong_t; +#endif + +#define ZORRO_WILDCARD (0xffffffff) /* not official */ + +#define ZORRO_DEVICE_MODALIAS_FMT "zorro:i%08X" + +struct zorro_device_id { + __u32 id; /* Device ID or ZORRO_WILDCARD */ + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + +#endif /* ifndef LINUX_DEVICE_ID_ZORRO_H */ diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h index 38048e74d10a..768a1334c0a1 100644 --- a/include/linux/device/driver.h +++ b/include/linux/device/driver.h @@ -19,6 +19,8 @@ #include #include #include +#include +#include /** * enum probe_type - device driver probe type to try diff --git a/include/linux/dfl.h b/include/linux/dfl.h index 1f02db0c1897..f28e70652080 100644 --- a/include/linux/dfl.h +++ b/include/linux/dfl.h @@ -9,7 +9,7 @@ #define __LINUX_DFL_H #include -#include +#include /** * enum dfl_id_type - define the DFL FIU types diff --git a/include/linux/dmi.h b/include/linux/dmi.h index c8700e6a694d..fbb62f7c3111 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h @@ -4,7 +4,7 @@ #include #include -#include +#include /* enum dmi_field is in mod_devicetable.h */ diff --git a/include/linux/eisa.h b/include/linux/eisa.h index cf55630b595b..52a97dc4c85a 100644 --- a/include/linux/eisa.h +++ b/include/linux/eisa.h @@ -4,7 +4,7 @@ #include #include -#include +#include #define EISA_MAX_SLOTS 8 diff --git a/include/linux/filter.h b/include/linux/filter.h index 67d337ede91b..14acb2455746 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -1314,6 +1315,15 @@ extern long bpf_jit_limit_max; typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size); +/* + * Flush the indirect branch predictors before reusing JIT memory, so that + * indirect jumps into a newly written program don't reuse predictions left + * behind by an old program that occupied the same space. + */ +void bpf_arch_pred_flush(void); +DECLARE_STATIC_CALL(bpf_arch_pred_flush, bpf_arch_pred_flush); +DECLARE_STATIC_KEY_FALSE(bpf_pred_flush_enabled); + void bpf_jit_fill_hole_with_zero(void *area, unsigned int size); struct bpf_binary_header * @@ -1328,7 +1338,7 @@ void bpf_jit_free(struct bpf_prog *fp); struct bpf_binary_header * bpf_jit_binary_pack_hdr(const struct bpf_prog *fp); -void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns); +void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic); void bpf_prog_pack_free(void *ptr, u32 size); static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp) @@ -1342,7 +1352,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **ro_image, unsigned int alignment, struct bpf_binary_header **rw_hdr, u8 **rw_image, - bpf_jit_fill_hole_t bpf_fill_ill_insns); + bpf_jit_fill_hole_t bpf_fill_ill_insns, + bool was_classic); int bpf_jit_binary_pack_finalize(struct bpf_binary_header *ro_header, struct bpf_binary_header *rw_header); void bpf_jit_binary_pack_free(struct bpf_binary_header *ro_header, diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 986d712e4d94..fd35a6570cd8 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -271,8 +272,6 @@ static inline void fw_unit_put(struct fw_unit *unit) #define fw_parent_device(unit) fw_device(unit->device.parent) -struct ieee1394_device_id; - struct fw_driver { struct device_driver driver; int (*probe)(struct fw_unit *unit, const struct ieee1394_device_id *id); diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h index 9f671e87c80c..c25f0f7e6dd4 100644 --- a/include/linux/fsl/mc.h +++ b/include/linux/fsl/mc.h @@ -11,7 +11,7 @@ #define _FSL_MC_H_ #include -#include +#include #include #include diff --git a/include/linux/hid.h b/include/linux/hid.h index 47dc0bc89fa4..b240baa95ab5 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -18,7 +18,7 @@ #include #include #include -#include /* hid_device_id */ +#include #include #include #include diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 9de2c8d6037a..a2b484679eb4 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 20fd41b51d5c..14ab4d3055af 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -12,7 +12,7 @@ #include /* for acpi_handle */ #include -#include +#include #include /* for struct device */ #include /* for completion */ #include diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h index 971d53349b6f..0f065b883ee0 100644 --- a/include/linux/i3c/device.h +++ b/include/linux/i3c/device.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include /** diff --git a/include/linux/input.h b/include/linux/input.h index 3022bb730898..76f7aa226202 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -19,7 +19,7 @@ #include #include #include -#include +#include struct input_dev_poller; diff --git a/include/linux/intel-ish-client-if.h b/include/linux/intel-ish-client-if.h index 2cd4f65aaa37..a07d952a2b29 100644 --- a/include/linux/intel-ish-client-if.h +++ b/include/linux/intel-ish-client-if.h @@ -9,7 +9,7 @@ #define _INTEL_ISH_CLIENT_IF_H_ #include -#include +#include struct ishtp_cl_device; struct ishtp_device; diff --git a/include/linux/iomap.h b/include/linux/iomap.h index 3582ed1fe236..56b43d594e6e 100644 --- a/include/linux/iomap.h +++ b/include/linux/iomap.h @@ -622,6 +622,8 @@ extern struct bio_set iomap_ioend_bioset; #ifdef CONFIG_BLOCK int iomap_bio_read_folio_range(const struct iomap_iter *iter, struct iomap_read_folio_ctx *ctx, size_t plen); +void iomap_bio_submit_read_endio(const struct iomap_iter *iter, + struct iomap_read_folio_ctx *ctx, bio_end_io_t end_io); extern const struct iomap_read_ops iomap_bio_read_ops; diff --git a/include/linux/ipack.h b/include/linux/ipack.h index 455f6c2a1903..7edbf9267338 100644 --- a/include/linux/ipack.h +++ b/include/linux/ipack.h @@ -6,7 +6,7 @@ * Author: Samuel Iglesias Gonsalvez */ -#include +#include #include #include diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h index dba18c95844b..8f5a85ca6c1f 100644 --- a/include/linux/isapnp.h +++ b/include/linux/isapnp.h @@ -28,7 +28,7 @@ */ #ifdef __KERNEL__ -#include +#include #define DEVICE_COUNT_COMPATIBLE 4 diff --git a/include/linux/mcb.h b/include/linux/mcb.h index 4ab2691f51a6..874118765d0f 100644 --- a/include/linux/mcb.h +++ b/include/linux/mcb.h @@ -8,7 +8,7 @@ #ifndef _LINUX_MCB_H #define _LINUX_MCB_H -#include +#include #include #include diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index 5bdbd9e1d460..d5d29451eabf 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -7,7 +7,7 @@ #include #include -#include +#include struct mei_cl_device; struct mei_device; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index fb3ba639f4f8..4b86ae6f6a82 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -14,6 +14,7 @@ #include #include #include +#include #define MHI_MAX_OEM_PK_HASH_SEGMENTS 16 diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h index 4534bf462aac..5d63a6465b0d 100644 --- a/include/linux/mmc/sdio_func.h +++ b/include/linux/mmc/sdio_func.h @@ -9,7 +9,7 @@ #define LINUX_MMC_SDIO_FUNC_H #include -#include +#include #include diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 3b0c9a251a2e..a397213bedac 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -9,706 +9,65 @@ #define LINUX_MOD_DEVICETABLE_H #ifdef __KERNEL__ -#include #include -#include -typedef unsigned long kernel_ulong_t; #endif -#define PCI_ANY_ID (~0) - -enum { - PCI_ID_F_VFIO_DRIVER_OVERRIDE = 1, -}; - -/** - * struct pci_device_id - PCI device ID structure - * @vendor: Vendor ID to match (or PCI_ANY_ID) - * @device: Device ID to match (or PCI_ANY_ID) - * @subvendor: Subsystem vendor ID to match (or PCI_ANY_ID) - * @subdevice: Subsystem device ID to match (or PCI_ANY_ID) - * @class: Device class, subclass, and "interface" to match. - * See Appendix D of the PCI Local Bus Spec or - * include/linux/pci_ids.h for a full list of classes. - * Most drivers do not need to specify class/class_mask - * as vendor/device is normally sufficient. - * @class_mask: Limit which sub-fields of the class field are compared. - * See drivers/scsi/sym53c8xx_2/ for example of usage. - * @driver_data: Data private to the driver. - * Most drivers don't need to use driver_data field. - * Best practice is to use driver_data as an index - * into a static list of equivalent device types, - * instead of using it as a pointer. - * @override_only: Match only when dev->driver_override is this driver. - */ -struct pci_device_id { - __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ - __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ - kernel_ulong_t driver_data; /* Data private to the driver */ - __u32 override_only; -}; - - -#define IEEE1394_MATCH_VENDOR_ID 0x0001 -#define IEEE1394_MATCH_MODEL_ID 0x0002 -#define IEEE1394_MATCH_SPECIFIER_ID 0x0004 -#define IEEE1394_MATCH_VERSION 0x0008 - -struct ieee1394_device_id { - __u32 match_flags; - __u32 vendor_id; - __u32 model_id; - __u32 specifier_id; - __u32 version; - union { - kernel_ulong_t driver_data; - const void *driver_data_ptr; - }; -}; - - -/* - * Device table entry for "new style" table-driven USB drivers. - * User mode code can read these tables to choose which modules to load. - * Declare the table as a MODULE_DEVICE_TABLE. - * - * A probe() parameter will point to a matching entry from this table. - * Use the driver_info field for each match to hold information tied - * to that match: device quirks, etc. - * - * Terminate the driver's table with an all-zeroes entry. - * Use the flag values to control which fields are compared. - */ - -/** - * struct usb_device_id - identifies USB devices for probing and hotplugging - * @match_flags: Bit mask controlling which of the other fields are used to - * match against new devices. Any field except for driver_info may be - * used, although some only make sense in conjunction with other fields. - * This is usually set by a USB_DEVICE_*() macro, which sets all - * other fields in this structure except for driver_info. - * @idVendor: USB vendor ID for a device; numbers are assigned - * by the USB forum to its members. - * @idProduct: Vendor-assigned product ID. - * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers. - * This is also used to identify individual product versions, for - * a range consisting of a single device. - * @bcdDevice_hi: High end of version number range. The range of product - * versions is inclusive. - * @bDeviceClass: Class of device; numbers are assigned - * by the USB forum. Products may choose to implement classes, - * or be vendor-specific. Device classes specify behavior of all - * the interfaces on a device. - * @bDeviceSubClass: Subclass of device; associated with bDeviceClass. - * @bDeviceProtocol: Protocol of device; associated with bDeviceClass. - * @bInterfaceClass: Class of interface; numbers are assigned - * by the USB forum. Products may choose to implement classes, - * or be vendor-specific. Interface classes specify behavior only - * of a given interface; other interfaces may support other classes. - * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass. - * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass. - * @bInterfaceNumber: Number of interface; composite devices may use - * fixed interface numbers to differentiate between vendor-specific - * interfaces. - * @driver_info: Holds information used by the driver. Usually it holds - * a pointer to a descriptor understood by the driver, or perhaps - * device flags. - * - * In most cases, drivers will create a table of device IDs by using - * USB_DEVICE(), or similar macros designed for that purpose. - * They will then export it to userspace using MODULE_DEVICE_TABLE(), - * and provide it to the USB core through their usb_driver structure. - * - * See the usb_match_id() function for information about how matches are - * performed. Briefly, you will normally use one of several macros to help - * construct these entries. Each entry you provide will either identify - * one or more specific products, or will identify a class of products - * which have agreed to behave the same. You should put the more specific - * matches towards the beginning of your table, so that driver_info can - * record quirks of specific products. - */ -struct usb_device_id { - /* which fields to match against? */ - __u16 match_flags; - - /* Used for product specific matches; range is inclusive */ - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice_lo; - __u16 bcdDevice_hi; - - /* Used for device class matches */ - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - - /* Used for interface class matches */ - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - - /* Used for vendor-specific interface matches */ - __u8 bInterfaceNumber; - - /* not matched against */ - kernel_ulong_t driver_info - __attribute__((aligned(sizeof(kernel_ulong_t)))); -}; - -/* Some useful macros to use to create struct usb_device_id */ -#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 -#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 -#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 -#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 -#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 -#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 -#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 -#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 -#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 -#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 -#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400 - -#define HID_ANY_ID (~0) -#define HID_BUS_ANY 0xffff -#define HID_GROUP_ANY 0x0000 - -struct hid_device_id { - __u16 bus; - __u16 group; - __u32 vendor; - __u32 product; - kernel_ulong_t driver_data; -}; - -/* s390 CCW devices */ -struct ccw_device_id { - __u16 match_flags; /* which fields to match against */ - - __u16 cu_type; /* control unit type */ - __u16 dev_type; /* device type */ - __u8 cu_model; /* control unit model */ - __u8 dev_model; /* device model */ - - kernel_ulong_t driver_info; -}; - -#define CCW_DEVICE_ID_MATCH_CU_TYPE 0x01 -#define CCW_DEVICE_ID_MATCH_CU_MODEL 0x02 -#define CCW_DEVICE_ID_MATCH_DEVICE_TYPE 0x04 -#define CCW_DEVICE_ID_MATCH_DEVICE_MODEL 0x08 - -/* s390 AP bus devices */ -struct ap_device_id { - __u16 match_flags; /* which fields to match against */ - __u8 dev_type; /* device type */ - kernel_ulong_t driver_info; -}; - -#define AP_DEVICE_ID_MATCH_CARD_TYPE 0x01 -#define AP_DEVICE_ID_MATCH_QUEUE_TYPE 0x02 - -/* s390 css bus devices (subchannels) */ -struct css_device_id { - __u8 match_flags; - __u8 type; /* subchannel type */ - kernel_ulong_t driver_data; -}; - -#define ACPI_ID_LEN 16 - -struct acpi_device_id { - __u8 id[ACPI_ID_LEN]; - kernel_ulong_t driver_data; - __u32 cls; - __u32 cls_msk; -}; - -/** - * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with - * the PCI-defined class-code information - * - * @_cls : the class, subclass, prog-if triple for this device - * @_msk : the class mask for this device - * - * This macro is used to create a struct acpi_device_id that matches a - * specific PCI class. The .id and .driver_data fields will be left - * initialized with the default value. - */ -#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (_cls), .cls_msk = (_msk), - -#define PNP_ID_LEN 8 -#define PNP_MAX_DEVICES 8 - -struct pnp_device_id { - __u8 id[PNP_ID_LEN]; - kernel_ulong_t driver_data; -}; - -struct pnp_card_device_id { - __u8 id[PNP_ID_LEN]; - kernel_ulong_t driver_data; - struct { - __u8 id[PNP_ID_LEN]; - } devs[PNP_MAX_DEVICES]; -}; - - -#define SERIO_ANY 0xff - -struct serio_device_id { - __u8 type; - __u8 extra; - __u8 id; - __u8 proto; -}; - -struct hda_device_id { - __u32 vendor_id; - __u32 rev_id; - __u8 api_version; - const char *name; - unsigned long driver_data; -}; - -struct sdw_device_id { - __u16 mfg_id; - __u16 part_id; - __u8 sdw_version; - __u8 class_id; - kernel_ulong_t driver_data; -}; - -/* - * Struct used for matching a device - */ -struct of_device_id { - char name[32]; - char type[32]; - char compatible[128]; - const void *data; -}; - -/* VIO */ -struct vio_device_id { - char type[32]; - char compat[32]; -}; - -/* PCMCIA */ - -struct pcmcia_device_id { - __u16 match_flags; - - __u16 manf_id; - __u16 card_id; - - __u8 func_id; - - /* for real multi-function devices */ - __u8 function; - - /* for pseudo multi-function devices */ - __u8 device_no; - - __u32 prod_id_hash[4]; - - /* not matched against in kernelspace */ - const char * prod_id[4]; - - /* not matched against */ - kernel_ulong_t driver_info; - char * cisfile; -}; - -#define PCMCIA_DEV_ID_MATCH_MANF_ID 0x0001 -#define PCMCIA_DEV_ID_MATCH_CARD_ID 0x0002 -#define PCMCIA_DEV_ID_MATCH_FUNC_ID 0x0004 -#define PCMCIA_DEV_ID_MATCH_FUNCTION 0x0008 -#define PCMCIA_DEV_ID_MATCH_PROD_ID1 0x0010 -#define PCMCIA_DEV_ID_MATCH_PROD_ID2 0x0020 -#define PCMCIA_DEV_ID_MATCH_PROD_ID3 0x0040 -#define PCMCIA_DEV_ID_MATCH_PROD_ID4 0x0080 -#define PCMCIA_DEV_ID_MATCH_DEVICE_NO 0x0100 -#define PCMCIA_DEV_ID_MATCH_FAKE_CIS 0x0200 -#define PCMCIA_DEV_ID_MATCH_ANONYMOUS 0x0400 - -/* Input */ -#define INPUT_DEVICE_ID_EV_MAX 0x1f -#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71 -#define INPUT_DEVICE_ID_KEY_MAX 0x2ff -#define INPUT_DEVICE_ID_REL_MAX 0x0f -#define INPUT_DEVICE_ID_ABS_MAX 0x3f -#define INPUT_DEVICE_ID_MSC_MAX 0x07 -#define INPUT_DEVICE_ID_LED_MAX 0x0f -#define INPUT_DEVICE_ID_SND_MAX 0x07 -#define INPUT_DEVICE_ID_FF_MAX 0x7f -#define INPUT_DEVICE_ID_SW_MAX 0x11 -#define INPUT_DEVICE_ID_PROP_MAX 0x1f - -#define INPUT_DEVICE_ID_MATCH_BUS 1 -#define INPUT_DEVICE_ID_MATCH_VENDOR 2 -#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 -#define INPUT_DEVICE_ID_MATCH_VERSION 8 - -#define INPUT_DEVICE_ID_MATCH_EVBIT 0x0010 -#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x0020 -#define INPUT_DEVICE_ID_MATCH_RELBIT 0x0040 -#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x0080 -#define INPUT_DEVICE_ID_MATCH_MSCIT 0x0100 -#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x0200 -#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x0400 -#define INPUT_DEVICE_ID_MATCH_FFBIT 0x0800 -#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000 -#define INPUT_DEVICE_ID_MATCH_PROPBIT 0x2000 - -struct input_device_id { - - kernel_ulong_t flags; - - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; - - kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t propbit[INPUT_DEVICE_ID_PROP_MAX / BITS_PER_LONG + 1]; - - kernel_ulong_t driver_info; -}; - -/* EISA */ - -#define EISA_SIG_LEN 8 - -/* The EISA signature, in ASCII form, null terminated */ -struct eisa_device_id { - char sig[EISA_SIG_LEN]; - kernel_ulong_t driver_data; -}; - -#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s" - -struct parisc_device_id { - __u8 hw_type; /* 5 bits used */ - __u8 hversion_rev; /* 4 bits */ - __u16 hversion; /* 12 bits */ - __u32 sversion; /* 20 bits */ -}; - -#define PA_HWTYPE_ANY_ID 0xff -#define PA_HVERSION_REV_ANY_ID 0xff -#define PA_HVERSION_ANY_ID 0xffff -#define PA_SVERSION_ANY_ID 0xffffffff - -/* SDIO */ - -#define SDIO_ANY_ID (~0) - -struct sdio_device_id { - __u8 class; /* Standard interface or SDIO_ANY_ID */ - __u16 vendor; /* Vendor or SDIO_ANY_ID */ - __u16 device; /* Device ID or SDIO_ANY_ID */ - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* SSB core, see drivers/ssb/ */ -struct ssb_device_id { - __u16 vendor; - __u16 coreid; - __u8 revision; - __u8 __pad; -} __attribute__((packed, aligned(2))); -#define SSB_DEVICE(_vendor, _coreid, _revision) \ - { .vendor = _vendor, .coreid = _coreid, .revision = _revision, } - -#define SSB_ANY_VENDOR 0xFFFF -#define SSB_ANY_ID 0xFFFF -#define SSB_ANY_REV 0xFF - -/* Broadcom's specific AMBA core, see drivers/bcma/ */ -struct bcma_device_id { - __u16 manuf; - __u16 id; - __u8 rev; - __u8 class; -} __attribute__((packed,aligned(2))); -#define BCMA_CORE(_manuf, _id, _rev, _class) \ - { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, } - -#define BCMA_ANY_MANUF 0xFFFF -#define BCMA_ANY_ID 0xFFFF -#define BCMA_ANY_REV 0xFF -#define BCMA_ANY_CLASS 0xFF - -struct virtio_device_id { - __u32 device; - __u32 vendor; -}; -#define VIRTIO_DEV_ANY_ID 0xffffffff - -/* - * For Hyper-V devices we use the device guid as the id. - */ -struct hv_vmbus_device_id { - guid_t guid; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* rpmsg */ - -#define RPMSG_NAME_SIZE 32 -#define RPMSG_DEVICE_MODALIAS_FMT "rpmsg:%s" - -struct rpmsg_device_id { - char name[RPMSG_NAME_SIZE]; - kernel_ulong_t driver_data; -}; - -/* i2c */ - -#define I2C_NAME_SIZE 20 -#define I2C_MODULE_PREFIX "i2c:" - -struct i2c_device_id { - char name[I2C_NAME_SIZE]; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* pci_epf */ - -#define PCI_EPF_NAME_SIZE 20 -#define PCI_EPF_MODULE_PREFIX "pci_epf:" - -struct pci_epf_device_id { - char name[PCI_EPF_NAME_SIZE]; - kernel_ulong_t driver_data; -}; - -/* i3c */ - -#define I3C_MATCH_DCR 0x1 -#define I3C_MATCH_MANUF 0x2 -#define I3C_MATCH_PART 0x4 -#define I3C_MATCH_EXTRA_INFO 0x8 - -struct i3c_device_id { - __u8 match_flags; - __u8 dcr; - __u16 manuf_id; - __u16 part_id; - __u16 extra_info; - - const void *data; -}; - -/* spi */ - -#define SPI_NAME_SIZE 32 -#define SPI_MODULE_PREFIX "spi:" - -struct spi_device_id { - char name[SPI_NAME_SIZE]; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* SLIMbus */ - -#define SLIMBUS_NAME_SIZE 32 -#define SLIMBUS_MODULE_PREFIX "slim:" - -struct slim_device_id { - __u16 manf_id, prod_code; - __u16 dev_index, instance; - - /* Data private to the driver */ - kernel_ulong_t driver_data; -}; - -#define APR_NAME_SIZE 32 -#define APR_MODULE_PREFIX "apr:" - -struct apr_device_id { - char name[APR_NAME_SIZE]; - __u32 domain_id; - __u32 svc_id; - __u32 svc_version; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -#define SPMI_NAME_SIZE 32 -#define SPMI_MODULE_PREFIX "spmi:" - -struct spmi_device_id { - char name[SPMI_NAME_SIZE]; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* dmi */ -enum dmi_field { - DMI_NONE, - DMI_BIOS_VENDOR, - DMI_BIOS_VERSION, - DMI_BIOS_DATE, - DMI_BIOS_RELEASE, - DMI_EC_FIRMWARE_RELEASE, - DMI_SYS_VENDOR, - DMI_PRODUCT_NAME, - DMI_PRODUCT_VERSION, - DMI_PRODUCT_SERIAL, - DMI_PRODUCT_UUID, - DMI_PRODUCT_SKU, - DMI_PRODUCT_FAMILY, - DMI_BOARD_VENDOR, - DMI_BOARD_NAME, - DMI_BOARD_VERSION, - DMI_BOARD_SERIAL, - DMI_BOARD_ASSET_TAG, - DMI_CHASSIS_VENDOR, - DMI_CHASSIS_TYPE, - DMI_CHASSIS_VERSION, - DMI_CHASSIS_SERIAL, - DMI_CHASSIS_ASSET_TAG, - DMI_STRING_MAX, - DMI_OEM_STRING, /* special case - will not be in dmi_ident */ -}; - -struct dmi_strmatch { - unsigned char slot:7; - unsigned char exact_match:1; - char substr[79]; -}; - -struct dmi_system_id { - int (*callback)(const struct dmi_system_id *); - const char *ident; - struct dmi_strmatch matches[4]; - void *driver_data; -}; -/* - * struct dmi_device_id appears during expansion of - * "MODULE_DEVICE_TABLE(dmi, x)". Compiler doesn't look inside it - * but this is enough for gcc 3.4.6 to error out: - * error: storage size of '__mod_dmi_device_table' isn't known - */ -#define dmi_device_id dmi_system_id - -#define DMI_MATCH(a, b) { .slot = a, .substr = b } -#define DMI_EXACT_MATCH(a, b) { .slot = a, .substr = b, .exact_match = 1 } - -#define PLATFORM_NAME_SIZE 24 -#define PLATFORM_MODULE_PREFIX "platform:" - -struct platform_device_id { - char name[PLATFORM_NAME_SIZE]; - kernel_ulong_t driver_data; -}; - -#define MDIO_MODULE_PREFIX "mdio:" - -#define MDIO_ID_FMT "%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u" -#define MDIO_ID_ARGS(_id) \ - ((_id)>>31) & 1, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \ - ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \ - ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \ - ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \ - ((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \ - ((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \ - ((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \ - ((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1 - -/** - * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus - * @phy_id: The result of - * (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&MII_PHYSID2)) & @phy_id_mask - * for this PHY type - * @phy_id_mask: Defines the significant bits of @phy_id. A value of 0 - * is used to terminate an array of struct mdio_device_id. - */ -struct mdio_device_id { - __u32 phy_id; - __u32 phy_id_mask; -}; - -struct zorro_device_id { - __u32 id; /* Device ID or ZORRO_WILDCARD */ - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -#define ZORRO_WILDCARD (0xffffffff) /* not official */ - -#define ZORRO_DEVICE_MODALIAS_FMT "zorro:i%08X" - -#define ISAPNP_ANY_ID 0xffff -struct isapnp_device_id { - unsigned short card_vendor, card_device; - unsigned short vendor, function; - kernel_ulong_t driver_data; /* data private to the driver */ -}; - -/** - * struct amba_id - identifies a device on an AMBA bus - * @id: The significant bits if the hardware device ID - * @mask: Bitmask specifying which bits of the id field are significant when - * matching. A driver binds to a device when ((hardware device ID) & mask) - * == id. - * @data: Private data used by the driver. - */ -struct amba_id { - unsigned int id; - unsigned int mask; - void *data; -}; - -/** - * struct mips_cdmm_device_id - identifies devices in MIPS CDMM bus - * @type: Device type identifier. - */ -struct mips_cdmm_device_id { - __u8 type; -}; - -/* - * Match x86 CPUs for CPU specific drivers. - * See documentation of "x86_match_cpu" for details. - */ - -/* - * MODULE_DEVICE_TABLE expects this struct to be called x86cpu_device_id. - * Although gcc seems to ignore this error, clang fails without this define. - */ -#define x86cpu_device_id x86_cpu_id -struct x86_cpu_id { - __u16 vendor; - __u16 family; - __u16 model; - __u16 steppings; - __u16 feature; /* bit index */ - /* Solely for kernel-internal use: DO NOT EXPORT to userspace! */ - __u16 flags; - __u8 platform_mask; - __u8 type; - kernel_ulong_t driver_data; -}; - -/* Wild cards for x86_cpu_id::vendor, family, model and feature */ -#define X86_VENDOR_ANY 0xffff -#define X86_FAMILY_ANY 0 -#define X86_MODEL_ANY 0 -#define X86_STEPPING_ANY 0 -#define X86_STEP_MIN 0 -#define X86_STEP_MAX 0xf -#define X86_PLATFORM_ANY 0x0 -#define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ -#define X86_CPU_TYPE_ANY 0 +#include "device-id/acpi.h" +#include "device-id/amba.h" +#include "device-id/ap.h" +#include "device-id/apr.h" +#include "device-id/auxiliary.h" +#include "device-id/bcma.h" +#include "device-id/ccw.h" +#include "device-id/cdx.h" +#include "device-id/coreboot.h" +#include "device-id/css.h" +#include "device-id/dfl.h" +#include "device-id/dmi.h" +#include "device-id/eisa.h" +#include "device-id/fsl_mc.h" +#include "device-id/hda.h" +#include "device-id/hid.h" +#include "device-id/hv_vmbus.h" +#include "device-id/i2c.h" +#include "device-id/i3c.h" +#include "device-id/ieee1394.h" +#include "device-id/input.h" +#include "device-id/ipack.h" +#include "device-id/isapnp.h" +#include "device-id/ishtp.h" +#include "device-id/mcb.h" +#include "device-id/mdio.h" +#include "device-id/mei_cl.h" +#include "device-id/mhi.h" +#include "device-id/mips_cdmm.h" +#include "device-id/of.h" +#include "device-id/parisc.h" +#include "device-id/pci.h" +#include "device-id/pcmcia.h" +#include "device-id/platform.h" +#include "device-id/pnp.h" +#include "device-id/rio.h" +#include "device-id/rpmsg.h" +#include "device-id/sdio.h" +#include "device-id/sdw.h" +#include "device-id/serio.h" +#include "device-id/slim.h" +#include "device-id/spi.h" +#include "device-id/spmi.h" +#include "device-id/ssam.h" +#include "device-id/ssb.h" +#include "device-id/tb.h" +#include "device-id/tee_client.h" +#include "device-id/typec.h" +#include "device-id/ulpi.h" +#include "device-id/usb.h" +#include "device-id/vchiq.h" +#include "device-id/vio.h" +#include "device-id/virtio.h" +#include "device-id/wmi.h" +#include "device-id/x86_cpu.h" +#include "device-id/zorro.h" /* * Generic table type for matching CPU features. @@ -719,265 +78,4 @@ struct cpu_feature { __u16 feature; }; -#define IPACK_ANY_FORMAT 0xff -#define IPACK_ANY_ID (~0) -struct ipack_device_id { - __u8 format; /* Format version or IPACK_ANY_ID */ - __u32 vendor; /* Vendor ID or IPACK_ANY_ID */ - __u32 device; /* Device ID or IPACK_ANY_ID */ -}; - -#define MEI_CL_MODULE_PREFIX "mei:" -#define MEI_CL_NAME_SIZE 32 -#define MEI_CL_VERSION_ANY 0xff - -/** - * struct mei_cl_device_id - MEI client device identifier - * @name: helper name - * @uuid: client uuid - * @version: client protocol version - * @driver_info: information used by the driver. - * - * identifies mei client device by uuid and name - */ -struct mei_cl_device_id { - char name[MEI_CL_NAME_SIZE]; - uuid_le uuid; - __u8 version; - kernel_ulong_t driver_info; -}; - -/* RapidIO */ - -#define RIO_ANY_ID 0xffff - -/** - * struct rio_device_id - RIO device identifier - * @did: RapidIO device ID - * @vid: RapidIO vendor ID - * @asm_did: RapidIO assembly device ID - * @asm_vid: RapidIO assembly vendor ID - * - * Identifies a RapidIO device based on both the device/vendor IDs and - * the assembly device/vendor IDs. - */ -struct rio_device_id { - __u16 did, vid; - __u16 asm_did, asm_vid; -}; - -struct mcb_device_id { - __u16 device; - kernel_ulong_t driver_data; -}; - -struct ulpi_device_id { - __u16 vendor; - __u16 product; - kernel_ulong_t driver_data; -}; - -/** - * struct fsl_mc_device_id - MC object device identifier - * @vendor: vendor ID - * @obj_type: MC object type - * - * Type of entries in the "device Id" table for MC object devices supported by - * a MC object device driver. The last entry of the table has vendor set to 0x0 - */ -struct fsl_mc_device_id { - __u16 vendor; - const char obj_type[16]; -}; - -/** - * struct tb_service_id - Thunderbolt service identifiers - * @match_flags: Flags used to match the structure - * @protocol_key: Protocol key the service supports - * @protocol_id: Protocol id the service supports - * @protocol_version: Version of the protocol - * @protocol_revision: Revision of the protocol software - * @driver_data: Driver specific data - * - * Thunderbolt XDomain services are exposed as devices where each device - * carries the protocol information the service supports. Thunderbolt - * XDomain service drivers match against that information. - */ -struct tb_service_id { - __u32 match_flags; - char protocol_key[8 + 1]; - __u32 protocol_id; - __u32 protocol_version; - __u32 protocol_revision; - kernel_ulong_t driver_data; -}; - -#define TBSVC_MATCH_PROTOCOL_KEY 0x0001 -#define TBSVC_MATCH_PROTOCOL_ID 0x0002 -#define TBSVC_MATCH_PROTOCOL_VERSION 0x0004 -#define TBSVC_MATCH_PROTOCOL_REVISION 0x0008 - -/* USB Type-C Alternate Modes */ - -#define TYPEC_ANY_MODE 0x7 - -/** - * struct typec_device_id - USB Type-C alternate mode identifiers - * @svid: Standard or Vendor ID - * @mode: Mode index - * @driver_data: Driver specific data - */ -struct typec_device_id { - __u16 svid; - __u8 mode; - kernel_ulong_t driver_data; -}; - -/** - * struct tee_client_device_id - tee based device identifier - * @uuid: For TEE based client devices we use the device uuid as - * the identifier. - */ -struct tee_client_device_id { - uuid_t uuid; -}; - -/* WMI */ - -#define WMI_MODULE_PREFIX "wmi:" - -/** - * struct wmi_device_id - WMI device identifier - * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba - * @context: pointer to driver specific data - */ -struct wmi_device_id { - const char guid_string[UUID_STRING_LEN+1]; - const void *context; -}; - -#define MHI_DEVICE_MODALIAS_FMT "mhi:%s" -#define MHI_NAME_SIZE 32 - -#define MHI_EP_DEVICE_MODALIAS_FMT "mhi_ep:%s" - -/** - * struct mhi_device_id - MHI device identification - * @chan: MHI channel name - * @driver_data: driver data; - */ -struct mhi_device_id { - const char chan[MHI_NAME_SIZE]; - kernel_ulong_t driver_data; -}; - -#define AUXILIARY_NAME_SIZE 40 -#define AUXILIARY_MODULE_PREFIX "auxiliary:" - -struct auxiliary_device_id { - char name[AUXILIARY_NAME_SIZE]; - kernel_ulong_t driver_data; -}; - -/* Surface System Aggregator Module */ - -#define SSAM_MATCH_TARGET 0x1 -#define SSAM_MATCH_INSTANCE 0x2 -#define SSAM_MATCH_FUNCTION 0x4 - -struct ssam_device_id { - __u8 match_flags; - - __u8 domain; - __u8 category; - __u8 target; - __u8 instance; - __u8 function; - - kernel_ulong_t driver_data; -}; - -/* - * DFL (Device Feature List) - * - * DFL defines a linked list of feature headers within the device MMIO space to - * provide an extensible way of adding features. Software can walk through these - * predefined data structures to enumerate features. It is now used in the FPGA. - * See Documentation/fpga/dfl.rst for more information. - * - * The dfl bus type is introduced to match the individual feature devices (dfl - * devices) for specific dfl drivers. - */ - -/** - * struct dfl_device_id - dfl device identifier - * @type: DFL FIU type of the device. See enum dfl_id_type. - * @feature_id: feature identifier local to its DFL FIU type. - * @driver_data: driver specific data. - */ -struct dfl_device_id { - __u16 type; - __u16 feature_id; - kernel_ulong_t driver_data; -}; - -/* ISHTP (Integrated Sensor Hub Transport Protocol) */ - -#define ISHTP_MODULE_PREFIX "ishtp:" - -/** - * struct ishtp_device_id - ISHTP device identifier - * @guid: GUID of the device. - * @driver_data: pointer to driver specific data - */ -struct ishtp_device_id { - guid_t guid; - kernel_ulong_t driver_data; -}; - -#define CDX_ANY_ID (0xFFFF) - -enum { - CDX_ID_F_VFIO_DRIVER_OVERRIDE = 1, -}; - -/** - * struct cdx_device_id - CDX device identifier - * @vendor: Vendor ID - * @device: Device ID - * @subvendor: Subsystem vendor ID (or CDX_ANY_ID) - * @subdevice: Subsystem device ID (or CDX_ANY_ID) - * @class: Device class - * Most drivers do not need to specify class/class_mask - * as vendor/device is normally sufficient. - * @class_mask: Limit which sub-fields of the class field are compared. - * @override_only: Match only when dev->driver_override is this driver. - * - * Type of entries in the "device Id" table for CDX devices supported by - * a CDX device driver. - */ -struct cdx_device_id { - __u16 vendor; - __u16 device; - __u16 subvendor; - __u16 subdevice; - __u32 class; - __u32 class_mask; - __u32 override_only; -}; - -struct vchiq_device_id { - char name[32]; -}; - -/** - * struct coreboot_device_id - Identifies a coreboot table entry - * @tag: tag ID - * @driver_data: driver specific data - */ -struct coreboot_device_id { - __u32 tag; - kernel_ulong_t driver_data; -}; - #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 243c0f737938..1bc120d61c5b 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -61,14 +61,16 @@ struct netfs_inode { #if IS_ENABLED(CONFIG_FSCACHE) struct fscache_cookie *cache; #endif - struct mutex wb_lock; /* Writeback serialisation */ + struct list_head wb_queue; /* Queue of processes wanting to do writeback */ loff_t _remote_i_size; /* Size of the remote file */ loff_t _zero_point; /* Size after which we assume there's no data * on the server */ + spinlock_t lock; /* Lock covering wb_queue */ atomic_t io_count; /* Number of outstanding reqs */ unsigned long flags; #define NETFS_ICTX_ODIRECT 0 /* The file has DIO in progress */ #define NETFS_ICTX_UNBUFFERED 1 /* I/O should not use the pagecache */ +#define NETFS_ICTX_WB_LOCK 2 /* Writeback serialisation lock */ #define NETFS_ICTX_MODIFIED_ATTR 3 /* Indicate change in mtime/ctime */ #define NETFS_ICTX_SINGLE_NO_UPLOAD 4 /* Monolithic payload, cache but no upload */ }; @@ -462,6 +464,10 @@ int netfs_alloc_folioq_buffer(struct address_space *mapping, size_t *_cur_size, ssize_t size, gfp_t gfp); void netfs_free_folioq_buffer(struct folio_queue *fq); +/* Writeback exclusion API. */ +bool netfs_wb_begin(struct netfs_inode *ictx, bool nowait); +void netfs_wb_end(struct netfs_inode *ictx); + /** * netfs_inode - Get the netfs inode context from the inode * @inode: The inode to query @@ -743,7 +749,8 @@ static inline void netfs_inode_init(struct netfs_inode *ctx, #if IS_ENABLED(CONFIG_FSCACHE) ctx->cache = NULL; #endif - mutex_init(&ctx->wb_lock); + INIT_LIST_HEAD(&ctx->wb_queue); + spin_lock_init(&ctx->lock); /* ->releasepage() drives zero_point */ if (use_zero_point) { ctx->_zero_point = ctx->_remote_i_size; @@ -753,7 +760,7 @@ static inline void netfs_inode_init(struct netfs_inode *ctx, /** * netfs_resize_file - Note that a file got resized - * @ctx: The netfs inode being resized + * @ictx: The netfs inode being resized * @new_i_size: The new file size * @changed_on_server: The change was applied to the server * diff --git a/include/linux/of.h b/include/linux/of.h index 20e4f752d5b6..b920aac6b975 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 17471ef8e092..181c438a9b0a 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -6,7 +6,9 @@ * */ -#include +#include +#include +#include struct device; struct device_node; diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h index 8a6c64a35890..704e1dc8b30a 100644 --- a/include/linux/pci-epf.h +++ b/include/linux/pci-epf.h @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include diff --git a/include/linux/pci.h b/include/linux/pci.h index ebb5b9d76360..64b308b6e61c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -24,7 +24,7 @@ #define LINUX_PCI_H #include -#include +#include #include #include diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 48d851fbd8ea..5842552294c1 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1791,22 +1791,8 @@ static inline int perf_is_paranoid(void) } extern int perf_allow_kernel(void); - -static inline int perf_allow_cpu(void) -{ - if (sysctl_perf_event_paranoid > 0 && !perfmon_capable()) - return -EACCES; - - return security_perf_event_open(PERF_SECURITY_CPU); -} - -static inline int perf_allow_tracepoint(void) -{ - if (sysctl_perf_event_paranoid > -1 && !perfmon_capable()) - return -EPERM; - - return security_perf_event_open(PERF_SECURITY_TRACEPOINT); -} +extern int perf_allow_cpu(void); +extern int perf_allow_tracepoint(void); extern int perf_exclude_event(struct perf_event *event, struct pt_regs *regs); @@ -2023,6 +2009,19 @@ perf_event_pause(struct perf_event *event, bool reset) { return 0; } static inline int perf_exclude_event(struct perf_event *event, struct pt_regs *regs) { return 0; } +static inline int perf_allow_kernel(void) +{ + return perfmon_capable() ? 0 : -EACCES; +} +static inline int perf_allow_cpu(void) +{ + return perfmon_capable() ? 0 : -EACCES; +} +static inline int perf_allow_tracepoint(void) +{ + return perfmon_capable() ? 0 : -EPERM; +} + #endif /* !CONFIG_PERF_EVENTS */ #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) diff --git a/include/linux/phy.h b/include/linux/phy.h index 199a7aaa341b..fc680901275b 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/platform_data/x86/int3472.h b/include/linux/platform_data/x86/int3472.h index 93f1e1fe09b4..a73841dfae27 100644 --- a/include/linux/platform_data/x86/int3472.h +++ b/include/linux/platform_data/x86/int3472.h @@ -13,6 +13,7 @@ #include #include #include +#include #include /* FIXME drop this once the I2C_DEV_NAME_FORMAT macro has been added to include/linux/i2c.h */ @@ -72,7 +73,6 @@ container_of(clk, struct int3472_discrete_device, clock) struct acpi_device; -struct dmi_system_id; struct i2c_client; struct platform_device; diff --git a/include/linux/platform_data/x86/soc.h b/include/linux/platform_data/x86/soc.h index f981907a5cb0..a6a6b313dfa7 100644 --- a/include/linux/platform_data/x86/soc.h +++ b/include/linux/platform_data/x86/soc.h @@ -12,7 +12,7 @@ #if IS_ENABLED(CONFIG_X86) -#include +#include #include diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h index 26e6a43358e2..8c566f09d04e 100644 --- a/include/linux/platform_device.h +++ b/include/linux/platform_device.h @@ -11,6 +11,7 @@ #define _PLATFORM_DEVICE_H_ #include +#include #define PLATFORM_DEVID_NONE (-1) #define PLATFORM_DEVID_AUTO (-2) @@ -18,7 +19,6 @@ struct irq_affinity; struct mfd_cell; struct property_entry; -struct platform_device_id; struct platform_device { const char *name; diff --git a/include/linux/pnp.h b/include/linux/pnp.h index 23fe3eaf242d..e0c0d17eb7d8 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #define PNP_NAME_LEN 50 diff --git a/include/linux/raspberrypi/vchiq_bus.h b/include/linux/raspberrypi/vchiq_bus.h index 9de179b39f85..e52291a3b247 100644 --- a/include/linux/raspberrypi/vchiq_bus.h +++ b/include/linux/raspberrypi/vchiq_bus.h @@ -7,7 +7,7 @@ #define _VCHIQ_DEVICE_H #include -#include +#include struct vchiq_drv_mgmt; diff --git a/include/linux/rio.h b/include/linux/rio.h index 2c29f21ba9e5..f42379775ce8 100644 --- a/include/linux/rio.h +++ b/include/linux/rio.h @@ -16,7 +16,7 @@ #include #include #include -#include +#include #ifdef CONFIG_RAPIDIO_DMA_ENGINE #include #endif diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h index 2e40eb54155e..0171c490339c 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/serio.h b/include/linux/serio.h index 69a47674af65..98be7084412c 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include extern const struct bus_type serio_bus; diff --git a/include/linux/slimbus.h b/include/linux/slimbus.h index a4608d9a9684..ca6f1da4bdf3 100644 --- a/include/linux/slimbus.h +++ b/include/linux/slimbus.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include extern const struct bus_type slimbus_bus; diff --git a/include/linux/soc/qcom/apr.h b/include/linux/soc/qcom/apr.h index 58fa1df96347..909e84f84e0c 100644 --- a/include/linux/soc/qcom/apr.h +++ b/include/linux/soc/qcom/apr.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index b484784e2690..79dd44922fbc 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index f6ed93eff00b..4c285d3ede1d 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -12,7 +12,9 @@ #include #include #include -#include +#include +#include +#include #include #include #include diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index e1fb11e0f12c..7fee9afa9458 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h index 8cd8c38cf3f3..ed6b271e5a73 100644 --- a/include/linux/surface_aggregator/device.h +++ b/include/linux/surface_aggregator/device.h @@ -14,7 +14,7 @@ #define _LINUX_SURFACE_AGGREGATOR_DEVICE_H #include -#include +#include #include #include diff --git a/include/linux/tee_drv.h b/include/linux/tee_drv.h index e561a26f537a..f3c5e106d853 100644 --- a/include/linux/tee_drv.h +++ b/include/linux/tee_drv.h @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h index feb1af175cfd..557288c0274b 100644 --- a/include/linux/thunderbolt.h +++ b/include/linux/thunderbolt.h @@ -23,7 +23,7 @@ struct device; #include #include #include -#include +#include #include #include #include diff --git a/include/linux/ulpi/driver.h b/include/linux/ulpi/driver.h index a8cb617a3028..c668d9c8d876 100644 --- a/include/linux/ulpi/driver.h +++ b/include/linux/ulpi/driver.h @@ -2,7 +2,7 @@ #ifndef __LINUX_ULPI_DRIVER_H #define __LINUX_ULPI_DRIVER_H -#include +#include #include diff --git a/include/linux/usb.h b/include/linux/usb.h index 25a203ac7a7e..1da4ad1610bc 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -2,7 +2,7 @@ #ifndef __LINUX_USB_H #define __LINUX_USB_H -#include +#include #include #define USB_MAJOR 180 diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 75b2b763f1ba..534e6650e2aa 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -13,6 +13,7 @@ #include #include #include +#include /* The maximum number of ports one device can grab at once */ #define MAX_NUM_PORTS 16 diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h index b90cc5cfff8d..ef21ead551be 100644 --- a/include/linux/usb/typec_altmode.h +++ b/include/linux/usb/typec_altmode.h @@ -3,7 +3,7 @@ #ifndef __USB_TYPEC_ALTMODE_H #define __USB_TYPEC_ALTMODE_H -#include +#include #include #include diff --git a/include/linux/vfio_pci_core.h b/include/linux/vfio_pci_core.h index 5fc6ce4dd786..9a1674c152aa 100644 --- a/include/linux/vfio_pci_core.h +++ b/include/linux/vfio_pci_core.h @@ -101,6 +101,9 @@ struct vfio_pci_core_device { const struct vfio_pci_device_ops *pci_ops; void __iomem *barmap[PCI_STD_NUM_BARS]; bool bar_mmap_supported[PCI_STD_NUM_BARS]; + /* Flags modified at runtime - dedicated storage unit */ + bool virq_disabled; + bool bardirty; u8 *pci_config_map; u8 *vconfig; struct perm_bits *msi_perm; @@ -115,18 +118,21 @@ struct vfio_pci_core_device { u16 msix_size; u32 msix_offset; u32 rbar[7]; + /* Flags only modified on setup/release - bitfield ok */ bool has_dyn_msix:1; bool pci_2_3:1; - bool virq_disabled:1; bool reset_works:1; bool extended_caps:1; - bool bardirty:1; bool has_vga:1; - bool needs_reset:1; bool nointx:1; bool needs_pm_restore:1; - bool pm_intx_masked:1; - bool pm_runtime_engaged:1; + bool disable_idle_d3:1; + bool nointxmask:1; + bool disable_vga:1; + /* Flags modified at runtime - dedicated storage unit */ + bool needs_reset; + bool pm_intx_masked; + bool pm_runtime_engaged; bool sriov_active; struct pci_saved_state *pci_saved_state; struct pci_saved_state *pm_save; @@ -157,8 +163,6 @@ int vfio_pci_core_register_dev_region(struct vfio_pci_core_device *vdev, unsigned int type, unsigned int subtype, const struct vfio_pci_regops *ops, size_t size, u32 flags, void *data); -void vfio_pci_core_set_params(bool nointxmask, bool is_disable_vga, - bool is_disable_idle_d3); void vfio_pci_core_close_device(struct vfio_device *core_vdev); int vfio_pci_core_init_dev(struct vfio_device *core_vdev); void vfio_pci_core_release_dev(struct vfio_device *core_vdev); diff --git a/include/linux/virtio.h b/include/linux/virtio.h index bf089e51970e..93e573c56563 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/include/linux/wmi.h b/include/linux/wmi.h index d723e4b1cafb..defcb624a7e2 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include /** diff --git a/include/linux/zorro.h b/include/linux/zorro.h index f36c8d39553d..4514c3109deb 100644 --- a/include/linux/zorro.h +++ b/include/linux/zorro.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include diff --git a/include/net/tcp_ao.h b/include/net/tcp_ao.h index 29fd7b735afa..9a2333e62e99 100644 --- a/include/net/tcp_ao.h +++ b/include/net/tcp_ao.h @@ -145,6 +145,7 @@ struct tcp_ao_info { u32 snd_sne; u32 rcv_sne; refcount_t refcnt; /* Protects twsk destruction */ + struct rcu_head rcu; }; #ifdef CONFIG_TCP_MD5SIG diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index b7a8de88b3c0..8ae92602e12f 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h @@ -14,7 +14,7 @@ #define _LINUX_DS_H #ifdef __KERNEL__ -#include +#include #endif #include diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 17945ab5e6e2..b4e327877739 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -9,7 +9,7 @@ #define __SOUND_HDA_CODEC_H #include -#include +#include #include #include #include diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index f11bfc6b9f42..aa994d6e6d35 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/include/uapi/drm/amdgpu_drm.h b/include/uapi/drm/amdgpu_drm.h index 9f3090db2f16..b32c72a662b6 100644 --- a/include/uapi/drm/amdgpu_drm.h +++ b/include/uapi/drm/amdgpu_drm.h @@ -58,6 +58,7 @@ extern "C" { #define DRM_AMDGPU_USERQ_SIGNAL 0x17 #define DRM_AMDGPU_USERQ_WAIT 0x18 #define DRM_AMDGPU_GEM_LIST_HANDLES 0x19 +#define DRM_AMDGPU_PROC_OPTIONS 0x1A #define DRM_IOCTL_AMDGPU_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_CREATE, union drm_amdgpu_gem_create) #define DRM_IOCTL_AMDGPU_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_MMAP, union drm_amdgpu_gem_mmap) @@ -79,6 +80,7 @@ extern "C" { #define DRM_IOCTL_AMDGPU_USERQ_SIGNAL DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ_SIGNAL, struct drm_amdgpu_userq_signal) #define DRM_IOCTL_AMDGPU_USERQ_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_USERQ_WAIT, struct drm_amdgpu_userq_wait) #define DRM_IOCTL_AMDGPU_GEM_LIST_HANDLES DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_GEM_LIST_HANDLES, struct drm_amdgpu_gem_list_handles) +#define DRM_IOCTL_AMDGPU_PROC_OPTIONS DRM_IOWR(DRM_COMMAND_BASE + DRM_AMDGPU_PROC_OPTIONS, struct drm_amdgpu_proc_options) /** * DOC: memory domains @@ -1673,6 +1675,25 @@ struct drm_amdgpu_info_uq_metadata { #define AMDGPU_FAMILY_GC_11_5_4 154 /* GC 11.5.4 */ #define AMDGPU_FAMILY_GC_12_0_0 152 /* GC 12.0.0 */ +/* + * Definition of user options + * + * option: AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY + * 0: Disable sigbus delay - SIGBUS will be raised immediately + * 0xFFFFFFFF: SIGBUS will not be raised + * other: Set the sigbus delay in milliseconds + */ +#define AMDGPU_PROC_OPTIONS_OP_KFD_SIGBUS_DELAY 0 + +#define AMDGPU_PROC_OPTIONS_KFD_SIGBUS_DELAY_DISABLED 0xFFFFFFFFu + +struct drm_amdgpu_proc_options { + __u32 op; + struct { + __u32 value; + } kfd_sigbus_delay; +}; + #if defined(__cplusplus) } #endif diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 48e9f1fdb78d..50c80af4ad4e 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -2589,6 +2589,12 @@ enum drm_xe_ras_error_component { DRM_XE_RAS_ERR_COMP_CORE_COMPUTE = 1, /** @DRM_XE_RAS_ERR_COMP_SOC_INTERNAL: SoC Internal Error */ DRM_XE_RAS_ERR_COMP_SOC_INTERNAL, + /** @DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY: Device Memory Error */ + DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY, + /** @DRM_XE_RAS_ERR_COMP_PCIE: PCIe Subsystem Error */ + DRM_XE_RAS_ERR_COMP_PCIE, + /** @DRM_XE_RAS_ERR_COMP_FABRIC: Fabric Subsystem Error */ + DRM_XE_RAS_ERR_COMP_FABRIC, /** @DRM_XE_RAS_ERR_COMP_MAX: Max Error */ DRM_XE_RAS_ERR_COMP_MAX /* non-ABI */ }; @@ -2606,7 +2612,10 @@ enum drm_xe_ras_error_component { */ #define DRM_XE_RAS_ERROR_COMPONENT_NAMES { \ [DRM_XE_RAS_ERR_COMP_CORE_COMPUTE] = "core-compute", \ - [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-internal" \ + [DRM_XE_RAS_ERR_COMP_SOC_INTERNAL] = "soc-internal", \ + [DRM_XE_RAS_ERR_COMP_DEVICE_MEMORY] = "device-memory", \ + [DRM_XE_RAS_ERR_COMP_PCIE] = "pcie", \ + [DRM_XE_RAS_ERR_COMP_FABRIC] = "fabric", \ } #if defined(__cplusplus) diff --git a/include/xen/interface/xen-mca.h b/include/xen/interface/xen-mca.h index 1c9afbe8cc26..8f5815f1d3ab 100644 --- a/include/xen/interface/xen-mca.h +++ b/include/xen/interface/xen-mca.h @@ -50,7 +50,7 @@ /* OUT: There was no machine check data to fetch. */ #define XEN_MC_NODATA 0x2 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ /* vIRQ injected to Dom0 */ #define VIRQ_MCA VIRQ_ARCH_0 @@ -388,5 +388,5 @@ struct xen_mce_log { #define MCE_GET_LOG_LEN _IOR('M', 2, int) #define MCE_GETCLEAR_FLAGS _IOR('M', 3, int) -#endif /* __ASSEMBLY__ */ +#endif /* __ASSEMBLER__ */ #endif /* __XEN_PUBLIC_ARCH_X86_MCA_H__ */ diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h index 0ca23eca2a9c..40c9793e9880 100644 --- a/include/xen/interface/xen.h +++ b/include/xen/interface/xen.h @@ -337,7 +337,7 @@ #define MMUEXT_MARK_SUPER 19 #define MMUEXT_UNMARK_SUPER 20 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ struct mmuext_op { unsigned int cmd; union { @@ -415,7 +415,7 @@ DEFINE_GUEST_HANDLE_STRUCT(mmuext_op); #define MAX_VMASST_TYPE 5 -#ifndef __ASSEMBLY__ +#ifndef __ASSEMBLER__ typedef uint16_t domid_t; @@ -760,11 +760,11 @@ struct tmem_op { DEFINE_GUEST_HANDLE(u64); -#else /* __ASSEMBLY__ */ +#else /* __ASSEMBLER__ */ /* In assembly code we cannot use C numeric constant suffixes. */ #define mk_unsigned_long(x) x -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLER__ */ #endif /* __XEN_PUBLIC_XEN_H__ */ diff --git a/kernel/bpf/bpf_inode_storage.c b/kernel/bpf/bpf_inode_storage.c index 0da8d923e39d..f9e81060c1f4 100644 --- a/kernel/bpf/bpf_inode_storage.c +++ b/kernel/bpf/bpf_inode_storage.c @@ -178,6 +178,15 @@ static int notsupp_get_next_key(struct bpf_map *map, void *key, static struct bpf_map *inode_storage_map_alloc(union bpf_attr *attr) { + /* + * Do not allow allocation of BPF_MAP_TYPE_INODE_STORAGE if the BPF LSM + * was not initialized by the LSM framework at boot. Without proper + * initialization, the BPF inode security blob offset remains unprepared, + * causing bpf_inode() to calculate an invalid memory offset and corrupt + * inode->i_security. + */ + if (!bpf_lsm_initialized) + return ERR_PTR(-EOPNOTSUPP); return bpf_local_storage_map_alloc(attr, &inode_cache); } diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 649cce41e13f..6e19a030da6f 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -875,6 +876,7 @@ int bpf_jit_add_poke_descriptor(struct bpf_prog *prog, struct bpf_prog_pack { struct list_head list; void *ptr; + bool arch_flush_needed; unsigned long bitmap[]; }; @@ -883,6 +885,15 @@ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size) memset(area, 0, size); } +DEFINE_STATIC_CALL_NULL(bpf_arch_pred_flush, bpf_arch_pred_flush); + +/* + * Enabled once bpf_arch_pred_flush points at a real flush routine. Lets the + * pack allocator test "is a predictor flush wired up at all" with a cheap + * static branch instead of repeatedly querying the static call target. + */ +DEFINE_STATIC_KEY_FALSE(bpf_pred_flush_enabled); + #define BPF_PROG_SIZE_TO_NBITS(size) (round_up(size, BPF_PROG_CHUNK_SIZE) / BPF_PROG_CHUNK_SIZE) static DEFINE_MUTEX(pack_mutex); @@ -918,6 +929,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins bpf_fill_ill_insns(pack->ptr, BPF_PROG_PACK_SIZE); bitmap_zero(pack->bitmap, BPF_PROG_PACK_SIZE / BPF_PROG_CHUNK_SIZE); + if (static_branch_unlikely(&bpf_pred_flush_enabled)) + pack->arch_flush_needed = true; set_vm_flush_reset_perms(pack->ptr); err = set_memory_rox((unsigned long)pack->ptr, BPF_PROG_PACK_SIZE / PAGE_SIZE); @@ -932,15 +945,23 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins return NULL; } -void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) +void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic) { unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size); - struct bpf_prog_pack *pack; - unsigned long pos; + struct bpf_prog_pack *pack, *fallback_pack = NULL; + unsigned long pos, fallback_pos = 0; void *ptr = NULL; mutex_lock(&pack_mutex); if (size > BPF_PROG_PACK_SIZE) { + /* + * Allocations larger than a pack get their own pages, and + * predictors are not flushed for such allocation. This is only + * safe because cBPF programs (the unprivileged attack surface) + * are bounded well below a pack size. + */ + if (was_classic && static_branch_unlikely(&bpf_pred_flush_enabled)) + pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n"); size = round_up(size, PAGE_SIZE); ptr = bpf_jit_alloc_exec(size); if (ptr) { @@ -960,8 +981,29 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) list_for_each_entry(pack, &pack_list, list) { pos = bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0, nbits, 0); - if (pos < BPF_PROG_CHUNK_COUNT) + if (pos >= BPF_PROG_CHUNK_COUNT) + continue; + /* Flush not enabled, use any pack */ + if (!static_branch_unlikely(&bpf_pred_flush_enabled)) goto found_free_area; + /* + * cBPF reuse of a dirty pack triggers a flush, so prefer a + * clean pack for cBPF. eBPF never flushes, so steer it to a + * dirty pack and keep clean packs free for cBPF. + */ + if (was_classic ^ pack->arch_flush_needed) + goto found_free_area; + if (!fallback_pack) { + fallback_pack = pack; + fallback_pos = pos; + } + } + + /* No preferred pack found */ + if (fallback_pack) { + pack = fallback_pack; + pos = fallback_pos; + goto found_free_area; } pack = alloc_new_pack(bpf_fill_ill_insns); @@ -971,6 +1013,16 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) pos = 0; found_free_area: + /* Flush only for cBPF as it may contain a crafted gadget */ + if (static_branch_unlikely(&bpf_pred_flush_enabled) && + pack->arch_flush_needed && + was_classic) { + struct bpf_prog_pack *p; + + static_call_cond(bpf_arch_pred_flush)(); + list_for_each_entry(p, &pack_list, list) + p->arch_flush_needed = false; + } bitmap_set(pack->bitmap, pos, nbits); ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT); @@ -1008,6 +1060,9 @@ void bpf_prog_pack_free(void *ptr, u32 size) "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n"); bitmap_clear(pack->bitmap, pos, nbits); + + if (static_branch_unlikely(&bpf_pred_flush_enabled)) + pack->arch_flush_needed = true; if (bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0, BPF_PROG_CHUNK_COUNT, 0) == 0) { list_del(&pack->list); @@ -1130,7 +1185,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr, unsigned int alignment, struct bpf_binary_header **rw_header, u8 **rw_image, - bpf_jit_fill_hole_t bpf_fill_ill_insns) + bpf_jit_fill_hole_t bpf_fill_ill_insns, + bool was_classic) { struct bpf_binary_header *ro_header; u32 size, hole, start; @@ -1143,7 +1199,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr, if (bpf_jit_charge_modmem(size)) return NULL; - ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns); + ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns, was_classic); if (!ro_header) { bpf_jit_uncharge_modmem(size); return NULL; diff --git a/kernel/bpf/disasm.c b/kernel/bpf/disasm.c index f8a3c7eb451e..0391b3bc0073 100644 --- a/kernel/bpf/disasm.c +++ b/kernel/bpf/disasm.c @@ -323,7 +323,10 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs, */ u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm; bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD || - insn->src_reg == BPF_PSEUDO_MAP_VALUE; + insn->src_reg == BPF_PSEUDO_MAP_VALUE || + insn->src_reg == BPF_PSEUDO_MAP_IDX || + insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE || + insn->src_reg == BPF_PSEUDO_BTF_ID; char tmp[64]; if (is_ptr && !allow_ptr_leaks) diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c index b77db7413f8c..ea2d60dc1fee 100644 --- a/kernel/bpf/dispatcher.c +++ b/kernel/bpf/dispatcher.c @@ -145,7 +145,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from, mutex_lock(&d->mutex); if (!d->image) { - d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero); + d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero, false); if (!d->image) goto out; d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE); diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 21a365d436a5..6515d4d3c003 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -7996,9 +7996,10 @@ reg_find_field_offset(const struct bpf_reg_state *reg, s32 off, u32 fields) return field; } -static int check_func_arg_reg_off(struct bpf_verifier_env *env, - const struct bpf_reg_state *reg, argno_t argno, - enum bpf_arg_type arg_type) +static int __check_func_arg_reg_off(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, argno_t argno, + enum bpf_arg_type arg_type, + bool btf_id_fixed_off_ok) { u32 type = reg->type; @@ -8055,12 +8056,11 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env, case PTR_TO_BTF_ID | MEM_ALLOC | NON_OWN_REF | MEM_RCU: /* When referenced PTR_TO_BTF_ID is passed to release function, * its fixed offset must be 0. In the other cases, fixed offset - * can be non-zero. This was already checked above. So pass - * fixed_off_ok as true to allow fixed offset for all other - * cases. var_off always must be 0 for PTR_TO_BTF_ID, hence we - * still need to do checks instead of returning. + * can be non-zero unless the caller requires otherwise. + * var_off always must be 0 for PTR_TO_BTF_ID, hence we still + * need to do checks instead of returning. */ - return __check_ptr_off_reg(env, reg, argno, true); + return __check_ptr_off_reg(env, reg, argno, btf_id_fixed_off_ok); case PTR_TO_CTX: /* * Allow fixed and variable offsets for syscall context, but @@ -8076,6 +8076,13 @@ static int check_func_arg_reg_off(struct bpf_verifier_env *env, } } +static int check_func_arg_reg_off(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, argno_t argno, + enum bpf_arg_type arg_type) +{ + return __check_func_arg_reg_off(env, reg, argno, arg_type, true); +} + static int check_arg_const_str(struct bpf_verifier_env *env, struct bpf_reg_state *reg, argno_t argno) { @@ -11947,6 +11954,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ enum bpf_arg_type arg_type = ARG_DONTCARE; argno_t argno = argno_from_arg(i + 1); int regno = reg_from_argno(argno); + bool btf_id_fixed_off_ok = true; u32 ref_id, type_size; bool is_ret_buf_sz = false; int kf_arg_type; @@ -12120,7 +12128,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ case KF_ARG_PTR_TO_MEM: case KF_ARG_PTR_TO_MEM_SIZE: case KF_ARG_PTR_TO_CALLBACK: - case KF_ARG_PTR_TO_REFCOUNTED_KPTR: case KF_ARG_PTR_TO_CONST_STR: case KF_ARG_PTR_TO_WORKQUEUE: case KF_ARG_PTR_TO_TIMER: @@ -12134,6 +12141,10 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ case KF_ARG_PTR_TO_CTX: arg_type = ARG_PTR_TO_CTX; break; + case KF_ARG_PTR_TO_REFCOUNTED_KPTR: + arg_type = ARG_PTR_TO_BTF_ID; + btf_id_fixed_off_ok = false; + break; default: verifier_bug(env, "unknown kfunc arg type %d", kf_arg_type); return -EFAULT; @@ -12141,7 +12152,8 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_ if (regno == meta->release_regno) arg_type |= OBJ_RELEASE; - ret = check_func_arg_reg_off(env, reg, argno, arg_type); + ret = __check_func_arg_reg_off(env, reg, argno, arg_type, + btf_id_fixed_off_ok); if (ret < 0) return ret; @@ -19994,13 +20006,13 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, if (!is_priv) mutex_unlock(&bpf_verifier_lock); bpf_clear_insn_aux_data(env, 0, env->prog->len); - vfree(env->insn_aux_data); err_free_env: bpf_stack_liveness_free(env); kvfree(env->cfg.insn_postorder); kvfree(env->scc_info); kvfree(env->succ); kvfree(env->gotox_tmp_buf); + vfree(env->insn_aux_data); kvfree(env); return ret; } diff --git a/kernel/events/core.c b/kernel/events/core.c index 954c36e28101..5d496acd4e1b 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4729,7 +4729,7 @@ static void perf_remove_from_owner(struct perf_event *event); static void perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx, struct task_struct *task, - bool revoke); + unsigned long detach_flags); /* * Removes all events from the current task that have been marked @@ -4756,7 +4756,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx) modified = true; - perf_event_exit_event(event, ctx, ctx->task, false); + perf_event_exit_event(event, ctx, ctx->task, DETACH_GROUP); } raw_spin_lock_irqsave(&ctx->lock, flags); @@ -12937,7 +12937,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event, /* * De-schedule the event and mark it REVOKED. */ - perf_event_exit_event(event, ctx, ctx->task, true); + perf_event_exit_event(event, ctx, ctx->task, DETACH_REVOKE); /* * All _free_event() bits that rely on event->pmu: @@ -14525,12 +14525,13 @@ static void perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx, struct task_struct *task, - bool revoke) + unsigned long detach_flags) { struct perf_event *parent_event = event->parent; - unsigned long detach_flags = DETACH_EXIT; unsigned int attach_state; + detach_flags |= DETACH_EXIT; + if (parent_event) { /* * Do not destroy the 'original' grouping; because of the @@ -14553,8 +14554,8 @@ perf_event_exit_event(struct perf_event *event, sync_child_event(event, task); } - if (revoke) - detach_flags |= DETACH_GROUP | DETACH_REVOKE; + if (detach_flags & DETACH_REVOKE) + detach_flags |= DETACH_GROUP; perf_remove_from_context(event, detach_flags); /* @@ -14642,7 +14643,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit) perf_event_task(task, ctx, 0); list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry) - perf_event_exit_event(child_event, ctx, exit ? task : NULL, false); + perf_event_exit_event(child_event, ctx, exit ? task : NULL, 0); mutex_unlock(&ctx->mutex); @@ -14768,6 +14769,24 @@ int perf_allow_kernel(void) } EXPORT_SYMBOL_GPL(perf_allow_kernel); +int perf_allow_cpu(void) +{ + if (sysctl_perf_event_paranoid > 0 && !perfmon_capable()) + return -EACCES; + + return security_perf_event_open(PERF_SECURITY_CPU); +} +EXPORT_SYMBOL_GPL(perf_allow_cpu); + +int perf_allow_tracepoint(void) +{ + if (sysctl_perf_event_paranoid > -1 && !perfmon_capable()) + return -EPERM; + + return security_perf_event_open(PERF_SECURITY_TRACEPOINT); +} +EXPORT_SYMBOL_GPL(perf_allow_tracepoint); + /* * Inherit an event from parent task to child task. * diff --git a/kernel/fork.c b/kernel/fork.c index 13e38e89a1f3..f0e2e131a9a5 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1009,6 +1009,11 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) tsk->mm_cid.active = 0; INIT_HLIST_NODE(&tsk->mm_cid.node); #endif + +#ifdef CONFIG_BPF_SYSCALL + RCU_INIT_POINTER(tsk->bpf_storage, NULL); + tsk->bpf_ctx = NULL; +#endif return tsk; free_stack: @@ -2247,10 +2252,6 @@ __latent_entropy struct task_struct *copy_process( p->sequential_io = 0; p->sequential_io_avg = 0; #endif -#ifdef CONFIG_BPF_SYSCALL - RCU_INIT_POINTER(p->bpf_storage, NULL); - p->bpf_ctx = NULL; -#endif unwind_task_init(p); diff --git a/kernel/futex/requeue.c b/kernel/futex/requeue.c index 7384672916fb..79823ad13683 100644 --- a/kernel/futex/requeue.c +++ b/kernel/futex/requeue.c @@ -645,12 +645,6 @@ int futex_requeue(u32 __user *uaddr1, unsigned int flags1, continue; } - /* Self-deadlock: non-top waiter already owns the PI futex. */ - if (rt_mutex_owner(&pi_state->pi_mutex) == this->task) { - ret = -EDEADLK; - break; - } - ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex, this->rt_waiter, this->task); diff --git a/kernel/trace/fprobe.c b/kernel/trace/fprobe.c index f378613ad120..f215990b9061 100644 --- a/kernel/trace/fprobe.c +++ b/kernel/trace/fprobe.c @@ -613,6 +613,16 @@ static int fprobe_fgraph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops continue; data_size = fp->entry_data_size; + /* + * The list may have grown since it was sized, so this node + * may not fit. Skip it as missed rather than overrun the + * reservation. + */ + if (fp->exit_handler && + used + FPROBE_HEADER_SIZE_IN_LONG + SIZE_IN_LONG(data_size) > reserved_words) { + fp->nmissed++; + continue; + } if (data_size && fp->exit_handler) data = fgraph_data + used + FPROBE_HEADER_SIZE_IN_LONG; else diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c index b66d6196338d..50518b071414 100644 --- a/kernel/trace/trace_eprobe.c +++ b/kernel/trace/trace_eprobe.c @@ -315,7 +315,7 @@ get_event_field(struct fetch_insn *code, void *rec) val = (unsigned long)addr; break; case FILTER_PTR_STRING: - val = (unsigned long)(*(char *)addr); + val = *(unsigned long *)addr; break; default: WARN_ON_ONCE(1); diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index fd1caa1f9723..d17cfee77d9c 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -342,10 +342,6 @@ static int parse_trace_event(char *arg, struct fetch_insn *code, ret = parse_trace_event_arg(arg, code, ctx); if (!ret) return 0; - if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { - code->op = FETCH_OP_COMM; - return 0; - } return -EINVAL; } @@ -678,7 +674,7 @@ static int parse_btf_arg(char *varname, int i, is_ptr, ret; u32 tid; - if (WARN_ON_ONCE(!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT))) + if (!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT)) return -EINVAL; is_ptr = split_next_field(varname, &field, ctx); @@ -1068,8 +1064,14 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, int len; if (ctx->flags & TPARG_FL_TEVENT) { - if (parse_trace_event(arg, code, ctx) < 0) + if (parse_trace_event(arg, code, ctx) < 0) { + /* 'comm' should be checked after field parsing. */ + if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { + code->op = FETCH_OP_COMM; + return 0; + } goto inval; + } return 0; } @@ -1241,6 +1243,7 @@ parse_probe_arg(char *arg, const struct fetch_type *type, code->op = FETCH_OP_FOFFS; code->immediate = (unsigned long)offset; // imm64? + offset = 0; } else { /* uprobes don't support symbols */ if (!(ctx->flags & TPARG_FL_KERNEL)) { diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 15758cc11fc6..0f09f7aaf93f 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -511,7 +511,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, C(NO_RETVAL, "This function returns 'void' type"), \ C(BAD_STACK_NUM, "Invalid stack number"), \ C(BAD_ARG_NUM, "Invalid argument number"), \ - C(BAD_VAR, "Invalid $-valiable specified"), \ + C(BAD_VAR, "Invalid $-variable specified"), \ C(BAD_REG_NAME, "Invalid register name"), \ C(BAD_MEM_ADDR, "Invalid memory address"), \ C(BAD_IMM, "Invalid immediate value"), \ diff --git a/lib/bootconfig.c b/lib/bootconfig.c index f445b7703fdd..2ed9ee3dc81c 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -427,10 +427,18 @@ static char xbc_namebuf[XBC_KEYLEN_MAX] __initdata; int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root) { struct xbc_node *knode, *vnode; - char *end = buf + size; const char *val, *q; + size_t len = 0; int ret; + /* + * Track the running written length rather than advancing @buf, so we + * never form "buf + size" or "buf += ret" while @buf is NULL (the + * size-probe call passes buf=NULL, size=0). NULL pointer arithmetic + * is undefined behavior and trips host UBSan / FORTIFY_SOURCE when + * this renderer runs at kernel build time. snprintf(NULL, 0, ...) + * itself is well defined and returns the would-be length. + */ xbc_node_for_each_key_value(root, knode, val) { ret = xbc_node_compose_key_after(root, knode, xbc_namebuf, XBC_KEYLEN_MAX); @@ -439,10 +447,11 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root) vnode = xbc_node_get_child(knode); if (!vnode) { - ret = snprintf(buf, rest(buf, end), "%s ", xbc_namebuf); + ret = snprintf(buf ? buf + len : NULL, rest(len, size), + "%s ", xbc_namebuf); if (ret < 0) return ret; - buf += ret; + len += ret; continue; } xbc_array_for_each_value(vnode, val) { @@ -452,15 +461,15 @@ int __init xbc_snprint_cmdline(char *buf, size_t size, struct xbc_node *root) * whitespace. */ q = strpbrk(val, " \t\r\n") ? "\"" : ""; - ret = snprintf(buf, rest(buf, end), "%s=%s%s%s ", - xbc_namebuf, q, val, q); + ret = snprintf(buf ? buf + len : NULL, rest(len, size), + "%s=%s%s%s ", xbc_namebuf, q, val, q); if (ret < 0) return ret; - buf += ret; + len += ret; } } - return buf - (end - size); + return len; } #undef rest diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 273919b16161..c2484551a4e8 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1568,6 +1568,7 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i, struct folio *folio; unsigned int nr = 0, offset; loff_t pos = i->xarray_start + i->iov_offset; + bool will_alloc = !*pages; XA_STATE(xas, i->xarray, pos >> PAGE_SHIFT); offset = pos & ~PAGE_MASK; @@ -1595,6 +1596,14 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i, } rcu_read_unlock(); + if (!nr) { + if (will_alloc) { + kvfree(*pages); + *pages = NULL; + } + return 0; + } + maxsize = min_t(size_t, nr * PAGE_SIZE - offset, maxsize); iov_iter_advance(i, maxsize); return maxsize; @@ -1628,6 +1637,8 @@ static ssize_t iov_iter_extract_bvec_pages(struct iov_iter *i, bi.bi_bvec_done = skip; maxpages = want_pages_array(pages, maxsize, skip, maxpages); + if (!maxpages) + return -ENOMEM; while (bi.bi_size && bi.bi_idx < i->nr_segs) { struct bio_vec bv = bvec_iter_bvec(i->bvec, bi); @@ -1745,6 +1756,7 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i, unsigned long addr; unsigned int gup_flags = 0; size_t offset; + bool will_alloc = !*pages; int res; if (i->data_source == ITER_DEST) @@ -1761,8 +1773,14 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i, if (!maxpages) return -ENOMEM; res = pin_user_pages_fast(addr, maxpages, gup_flags, *pages); - if (unlikely(res <= 0)) + if (unlikely(res <= 0)) { + if (will_alloc) { + kvfree(*pages); + *pages = NULL; + } return res; + } + maxsize = min_t(size_t, maxsize, res * PAGE_SIZE - offset); iov_iter_advance(i, maxsize); return maxsize; diff --git a/lib/raid/raid6/riscv/recov_rvv.c b/lib/raid/raid6/riscv/recov_rvv.c index 2305940276dd..78e158a3e332 100644 --- a/lib/raid/raid6/riscv/recov_rvv.c +++ b/lib/raid/raid6/riscv/recov_rvv.c @@ -8,6 +8,7 @@ #include #include "algos.h" #include "rvv.h" +#include "pq_arch.h" static void __raid6_2data_recov_rvv(int bytes, u8 *p, u8 *q, u8 *dp, u8 *dq, const u8 *pbmul, diff --git a/lib/raid/raid6/riscv/rvv.c b/lib/raid/raid6/riscv/rvv.c index 75c9dafedb28..4ac50606f3dc 100644 --- a/lib/raid/raid6/riscv/rvv.c +++ b/lib/raid/raid6/riscv/rvv.c @@ -10,6 +10,7 @@ */ #include "rvv.h" +#include "pq_arch.h" #ifdef __riscv_vector #error "This code must be built without compiler support for vector" diff --git a/lib/scatterlist.c b/lib/scatterlist.c index b7fe91ef35b8..6ea40d2e6247 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -1366,6 +1366,7 @@ static ssize_t extract_xarray_to_sg(struct iov_iter *iter, sg_max--; maxsize -= len; + start += len; ret += len; if (maxsize <= 0 || sg_max == 0) break; diff --git a/lib/tests/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c index 1e6fce9cb255..d9690ba1db88 100644 --- a/lib/tests/kunit_iov_iter.c +++ b/lib/tests/kunit_iov_iter.c @@ -283,7 +283,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test) struct page **spages, **bpages; u8 *scratch, *buffer; size_t bufsize, npages, size, copied; - int i, b, patt; + int i, patt; bufsize = 0x100000; npages = bufsize / PAGE_SIZE; @@ -306,10 +306,9 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test) KUNIT_EXPECT_EQ(test, iter.nr_segs, 0); /* Build the expected image in the scratch buffer. */ - b = 0; patt = 0; memset(scratch, 0, bufsize); - for (pr = bvec_test_ranges; pr->from >= 0; pr++, b++) { + for (pr = bvec_test_ranges; pr->from >= 0; pr++) { u8 *p = scratch + pr->page * PAGE_SIZE; for (i = pr->from; i < pr->to; i++) diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index ae39ceaa2e29..c40c9e02391b 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -1066,6 +1066,9 @@ static u16 batadv_arp_get_type(struct batadv_priv *bat_priv, * @skb: the buffer containing the packet to extract the VID from * @hdr_size: the size of the batman-adv header encapsulating the packet * + * The caller must ensure that at least @hdr_size + ETH_HLEN bytes are + * accessible after skb->data. + * * Return: If the packet embedded in the skb is vlan tagged this function * returns the VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS * is returned. @@ -1148,6 +1151,10 @@ bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; + /* first, find out the vid. */ + if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) + goto out; + vid = batadv_dat_get_vid(skb, &hdr_size); type = batadv_arp_get_type(bat_priv, skb, hdr_size); @@ -1243,6 +1250,10 @@ bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; + /* first, find out the vid. */ + if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) + goto out; + vid = batadv_dat_get_vid(skb, &hdr_size); type = batadv_arp_get_type(bat_priv, skb, hdr_size); @@ -1305,6 +1316,10 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, if (!READ_ONCE(bat_priv->distributed_arp_table)) return; + /* first, find out the vid. */ + if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) + return; + vid = batadv_dat_get_vid(skb, &hdr_size); type = batadv_arp_get_type(bat_priv, skb, hdr_size); @@ -1353,6 +1368,10 @@ bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, if (!READ_ONCE(bat_priv->distributed_arp_table)) goto out; + /* first, find out the vid. */ + if (!pskb_may_pull(skb, hdr_size + ETH_HLEN)) + goto out; + vid = batadv_dat_get_vid(skb, &hdr_size); type = batadv_arp_get_type(bat_priv, skb, hdr_size); @@ -1747,6 +1766,7 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv, struct ethhdr *ethhdr; __be32 ip_src, yiaddr; unsigned short vid; + int hdr_size_tmp; __be16 proto; u8 *hw_src; @@ -1763,8 +1783,10 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct batadv_priv *bat_priv, if (!batadv_dat_check_dhcp_ack(skb, proto, &ip_src, chaddr, &yiaddr)) return; + hdr_size_tmp = hdr_size; + vid = batadv_dat_get_vid(skb, &hdr_size_tmp); + ethhdr = (struct ethhdr *)(skb->data + hdr_size); hw_src = ethhdr->h_source; - vid = batadv_dat_get_vid(skb, &hdr_size); batadv_dat_entry_add(bat_priv, yiaddr, chaddr, vid); batadv_dat_entry_add(bat_priv, ip_src, hw_src, vid); @@ -1804,6 +1826,10 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, if (batadv_forw_packet_is_rebroadcast(forw_packet)) goto out; + /* first, find out the vid. */ + if (!pskb_may_pull(forw_packet->skb, hdr_size + ETH_HLEN)) + goto out; + vid = batadv_dat_get_vid(forw_packet->skb, &hdr_size); type = batadv_arp_get_type(bat_priv, forw_packet->skb, hdr_size); diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 305488a74a25..a5ac82eabd25 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -684,12 +684,13 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct batadv_gw_node *gw_node = NULL; struct batadv_gw_node *curr_gw = NULL; struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; - struct ethhdr *ethhdr = (struct ethhdr *)skb->data; + struct ethhdr *ethhdr; bool out_of_range = false; u8 curr_tq_avg; unsigned short vid; vid = batadv_get_vid(skb, 0); + ethhdr = (struct ethhdr *)skb->data; if (is_multicast_ether_addr(ethhdr->h_dest)) goto out; diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 3c4572284b53..4d3807a645b7 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -580,6 +580,9 @@ void batadv_recv_handler_unregister(u8 packet_type) * @skb: the buffer containing the packet * @header_len: length of the batman header preceding the ethernet header * + * The caller must ensure that at least @header_len + ETH_HLEN bytes are + * accessible after skb->data. + * * Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the * skb is vlan tagged. Otherwise BATADV_NO_FLAGS. */ diff --git a/net/batman-adv/mesh-interface.c b/net/batman-adv/mesh-interface.c index 44026810b99c..511f70e0706a 100644 --- a/net/batman-adv/mesh-interface.c +++ b/net/batman-adv/mesh-interface.c @@ -434,6 +434,7 @@ void batadv_interface_rx(struct net_device *mesh_iface, if (!pskb_may_pull(skb, VLAN_ETH_HLEN)) goto dropped; + ethhdr = eth_hdr(skb); vhdr = skb_vlan_eth_hdr(skb); /* drop batman-in-batman packets to prevent loops */ diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index c05fcc9241ad..bbd40fe3a8e5 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -855,8 +855,8 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, if (skb_cow(skb, sizeof(*unicast_packet)) < 0) return false; - unicast_packet = (struct batadv_unicast_packet *)skb->data; vid = batadv_get_vid(skb, hdr_len); + unicast_packet = (struct batadv_unicast_packet *)skb->data; ethhdr = (struct ethhdr *)(skb->data + hdr_len); /* do not reroute multicast frames in a unicast header */ @@ -1029,6 +1029,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, hdr_size); batadv_orig_node_put(orig_node_gw); if (is_gw) { + orig_addr_gw = eth_hdr(skb)->h_source; batadv_dbg(BATADV_DBG_BLA, bat_priv, "%s(): Dropped unicast pkt received from another backbone gw %pM.\n", __func__, orig_addr_gw); diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 7ed19aa8ae59..c52613431f88 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -392,6 +392,9 @@ void br_dev_delete(struct net_device *dev, struct list_head *head) br_fdb_delete_by_port(br, NULL, 0, 1); + timer_shutdown_sync(&br->hello_timer); + timer_shutdown_sync(&br->topology_change_timer); + timer_shutdown_sync(&br->tcn_timer); cancel_delayed_work_sync(&br->gc_work); br_sysfs_delbr(br->dev); diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c index 46919d73d42f..c7e7e924f155 100644 --- a/net/bridge/br_stp.c +++ b/net/bridge/br_stp.c @@ -382,7 +382,8 @@ void br_topology_change_detection(struct net_bridge *br) { int isroot = br_is_root_bridge(br); - if (br->stp_enabled != BR_KERNEL_STP) + if (br->stp_enabled != BR_KERNEL_STP || + !(br->dev->flags & IFF_UP)) return; br_info(br, "topology change detected, %s\n", diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 229dde818ab3..96d5945e6a30 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -633,14 +633,6 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head) container_of(rcu_head, struct netpoll_info, rcu); skb_queue_purge(&npinfo->txq); - - /* we can't call cancel_delayed_work_sync here, as we are in softirq */ - cancel_delayed_work(&npinfo->tx_work); - - /* clean after last, unfinished work */ - __skb_queue_purge(&npinfo->txq); - /* now cancel it again */ - cancel_delayed_work(&npinfo->tx_work); kfree(npinfo); } @@ -664,6 +656,7 @@ static void __netpoll_cleanup(struct netpoll *np) ops->ndo_netpoll_cleanup(np->dev); RCU_INIT_POINTER(np->dev->npinfo, NULL); + disable_delayed_work_sync(&npinfo->tx_work); call_rcu(&npinfo->rcu, rcu_cleanup_netpoll_info); } diff --git a/net/core/sock_map.c b/net/core/sock_map.c index 99e3789492a0..c60ba6d292f9 100644 --- a/net/core/sock_map.c +++ b/net/core/sock_map.c @@ -1515,6 +1515,17 @@ static int sock_map_prog_link_lookup(struct bpf_map *map, struct bpf_prog ***ppr return 0; } +static int sock_map_prog_attach_check(enum bpf_attach_type attach_type, + struct bpf_prog *prog) +{ + /* A stream parser must not modify the skb, only measure it. */ + if (prog && attach_type == BPF_SK_SKB_STREAM_PARSER && + prog->aux->changes_pkt_data) + return -EINVAL; + + return 0; +} + /* Handle the following four cases: * prog_attach: prog != NULL, old == NULL, link == NULL * prog_detach: prog == NULL, old != NULL, link == NULL @@ -1533,6 +1544,10 @@ static int sock_map_prog_update(struct bpf_map *map, struct bpf_prog *prog, if (ret) return ret; + ret = sock_map_prog_attach_check(which, prog); + if (ret) + return ret; + /* for prog_attach/prog_detach/link_attach, return error if a bpf_link * exists for that prog. */ @@ -1776,6 +1791,11 @@ static int sock_map_link_update_prog(struct bpf_link *link, ret = -EINVAL; goto out; } + + ret = sock_map_prog_attach_check(link->attach_type, prog); + if (ret) + goto out; + if (!sockmap_link->map) { ret = -ENOLINK; goto out; diff --git a/net/dsa/tag.c b/net/dsa/tag.c index 79ad105902d9..991732d6eae2 100644 --- a/net/dsa/tag.c +++ b/net/dsa/tag.c @@ -79,15 +79,16 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, if (likely(skb->dev)) { dsa_default_offload_fwd_mark(skb); nskb = skb; + } else { + /* Just drop the skb if we can't find the user */ + kfree_skb(skb); } } else { nskb = cpu_dp->rcv(skb, dev); } - if (!nskb) { - kfree_skb(skb); + if (!nskb) return 0; - } skb = nskb; skb_push(skb, ETH_HLEN); @@ -107,11 +108,10 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, if (unlikely(cpu_dp->ds->untag_bridge_pvid || cpu_dp->ds->untag_vlan_aware_bridge_pvid)) { + /* dsa_software_vlan_untag() drops skb on failure */ nskb = dsa_software_vlan_untag(skb); - if (!nskb) { - kfree_skb(skb); + if (!nskb) return 0; - } skb = nskb; } diff --git a/net/dsa/tag_ar9331.c b/net/dsa/tag_ar9331.c index cbb588ca73aa..2e2388143b02 100644 --- a/net/dsa/tag_ar9331.c +++ b/net/dsa/tag_ar9331.c @@ -51,8 +51,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb, u8 ver, port; u16 hdr; - if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN))) + if (unlikely(!pskb_may_pull(skb, AR9331_HDR_LEN))) { + kfree_skb(skb); return NULL; + } hdr = le16_to_cpu(*(__le16 *)skb_mac_header(skb)); @@ -60,12 +62,14 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb, if (unlikely(ver != AR9331_HDR_VERSION)) { netdev_warn_once(ndev, "%s:%i wrong header version 0x%2x\n", __func__, __LINE__, hdr); + kfree_skb(skb); return NULL; } if (unlikely(hdr & AR9331_HDR_FROM_CPU)) { netdev_warn_once(ndev, "%s:%i packet should not be from cpu 0x%2x\n", __func__, __LINE__, hdr); + kfree_skb(skb); return NULL; } @@ -75,8 +79,10 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb, port = FIELD_GET(AR9331_HDR_PORT_NUM_MASK, hdr); skb->dev = dsa_conduit_find_user(ndev, 0, port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } return skb; } diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c index cf9420439054..411e3b57d16a 100644 --- a/net/dsa/tag_brcm.c +++ b/net/dsa/tag_brcm.c @@ -102,9 +102,9 @@ static struct sk_buff *brcm_tag_xmit_ll(struct sk_buff *skb, * (including FCS and tag) because the length verification is done after * the Broadcom tag is stripped off the ingress packet. * - * Let dsa_user_xmit() free the SKB + * Free the SKB on error. */ - if (__skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN, false)) + if (skb_put_padto(skb, ETH_ZLEN + BRCM_TAG_LEN)) return NULL; skb_push(skb, BRCM_TAG_LEN); @@ -151,27 +151,35 @@ static struct sk_buff *brcm_tag_rcv_ll(struct sk_buff *skb, int source_port; u8 *brcm_tag; - if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) + if (unlikely(!pskb_may_pull(skb, BRCM_TAG_LEN))) { + kfree_skb(skb); return NULL; + } brcm_tag = skb->data - offset; /* The opcode should never be different than 0b000 */ - if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) + if (unlikely((brcm_tag[0] >> BRCM_OPCODE_SHIFT) & BRCM_OPCODE_MASK)) { + kfree_skb(skb); return NULL; + } /* We should never see a reserved reason code without knowing how to * handle it */ - if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD)) + if (unlikely(brcm_tag[2] & BRCM_EG_RC_RSVD)) { + kfree_skb(skb); return NULL; + } /* Locate which port this is coming from */ source_port = brcm_tag[3] & BRCM_EG_PID_MASK; skb->dev = dsa_conduit_find_user(dev, 0, source_port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } /* Remove Broadcom tag and update checksum */ skb_pull_rcsum(skb, BRCM_TAG_LEN); @@ -228,8 +236,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, __be16 *proto; u8 *brcm_tag; - if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) + if (unlikely(!pskb_may_pull(skb, BRCM_LEG_TAG_LEN + VLAN_HLEN))) { + kfree_skb(skb); return NULL; + } brcm_tag = dsa_etype_header_pos_rx(skb); proto = (__be16 *)(brcm_tag + BRCM_LEG_TAG_LEN); @@ -237,8 +247,10 @@ static struct sk_buff *brcm_leg_tag_rcv(struct sk_buff *skb, source_port = brcm_tag[5] & BRCM_LEG_PORT_ID; skb->dev = dsa_conduit_find_user(dev, 0, source_port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } /* The internal switch in BCM63XX SoCs always tags on egress on the CPU * port. We use VID 0 internally for untagged traffic, so strip the tag @@ -273,10 +285,8 @@ static struct sk_buff *brcm_leg_tag_xmit(struct sk_buff *skb, * need to make sure that packets are at least 70 bytes * (including FCS and tag) because the length verification is done after * the Broadcom tag is stripped off the ingress packet. - * - * Let dsa_user_xmit() free the SKB */ - if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) + if (skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN)) return NULL; skb_push(skb, BRCM_LEG_TAG_LEN); @@ -325,10 +335,8 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb, * need to make sure that packets are at least 70 bytes (including FCS * and tag) because the length verification is done after the Broadcom * tag is stripped off the ingress packet. - * - * Let dsa_user_xmit() free the SKB. */ - if (__skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN, false)) + if (skb_put_padto(skb, ETH_ZLEN + BRCM_LEG_TAG_LEN)) return NULL; fcs_len = skb->len; @@ -351,8 +359,9 @@ static struct sk_buff *brcm_leg_fcs_tag_xmit(struct sk_buff *skb, brcm_tag[5] = dp->index & BRCM_LEG_PORT_ID; /* Original FCS value */ - if (__skb_pad(skb, ETH_FCS_LEN, false)) + if (skb_pad(skb, ETH_FCS_LEN)) return NULL; + skb_put_data(skb, &fcs_val, ETH_FCS_LEN); return skb; diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index 2a2c4fb61a65..d5ffee35fbb5 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c @@ -224,6 +224,7 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev, /* Remote management is not implemented yet, * drop. */ + kfree_skb(skb); return NULL; case DSA_CODE_ARP_MIRROR: case DSA_CODE_POLICY_MIRROR: @@ -244,12 +245,14 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev, /* Reserved code, this could be anything. Drop * seems like the safest option. */ + kfree_skb(skb); return NULL; } break; default: + kfree_skb(skb); return NULL; } @@ -271,8 +274,10 @@ static struct sk_buff *dsa_rcv_ll(struct sk_buff *skb, struct net_device *dev, source_port); } - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } /* When using LAG offload, skb->dev is not a DSA user interface, * so we cannot call dsa_default_offload_fwd_mark and we need to @@ -335,8 +340,10 @@ static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev) static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev) { - if (unlikely(!pskb_may_pull(skb, DSA_HLEN))) + if (unlikely(!pskb_may_pull(skb, DSA_HLEN))) { + kfree_skb(skb); return NULL; + } return dsa_rcv_ll(skb, dev, 0); } @@ -375,8 +382,10 @@ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev) static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev) { - if (unlikely(!pskb_may_pull(skb, EDSA_HLEN))) + if (unlikely(!pskb_may_pull(skb, EDSA_HLEN))) { + kfree_skb(skb); return NULL; + } skb_pull_rcsum(skb, EDSA_HLEN - DSA_HLEN); diff --git a/net/dsa/tag_gswip.c b/net/dsa/tag_gswip.c index 5fa436121087..5c407d448c9f 100644 --- a/net/dsa/tag_gswip.c +++ b/net/dsa/tag_gswip.c @@ -80,16 +80,20 @@ static struct sk_buff *gswip_tag_rcv(struct sk_buff *skb, int port; u8 *gswip_tag; - if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) + if (unlikely(!pskb_may_pull(skb, GSWIP_RX_HEADER_LEN))) { + kfree_skb(skb); return NULL; + } gswip_tag = skb->data - ETH_HLEN; /* Get source port information */ port = (gswip_tag[7] & GSWIP_RX_SPPID_MASK) >> GSWIP_RX_SPPID_SHIFT; skb->dev = dsa_conduit_find_user(dev, 0, port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } /* remove GSWIP tag */ skb_pull_rcsum(skb, GSWIP_RX_HEADER_LEN); diff --git a/net/dsa/tag_hellcreek.c b/net/dsa/tag_hellcreek.c index 544ab15685a2..dd9f328f3182 100644 --- a/net/dsa/tag_hellcreek.c +++ b/net/dsa/tag_hellcreek.c @@ -27,8 +27,10 @@ static struct sk_buff *hellcreek_xmit(struct sk_buff *skb, * checksums after the switch strips the tag. */ if (skb->ip_summed == CHECKSUM_PARTIAL && - skb_checksum_help(skb)) + skb_checksum_help(skb)) { + kfree_skb(skb); return NULL; + } /* Tag encoding */ tag = skb_put(skb, HELLCREEK_TAG_LEN); @@ -47,11 +49,14 @@ static struct sk_buff *hellcreek_rcv(struct sk_buff *skb, skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) { netdev_warn_once(dev, "Failed to get source port: %d\n", port); + kfree_skb(skb); return NULL; } - if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN)) + if (pskb_trim_rcsum(skb, skb->len - HELLCREEK_TAG_LEN)) { + kfree_skb(skb); return NULL; + } dsa_default_offload_fwd_mark(skb); diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c index d2475c3bbb7d..67fa89f102e0 100644 --- a/net/dsa/tag_ksz.c +++ b/net/dsa/tag_ksz.c @@ -88,11 +88,15 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, unsigned int port, unsigned int len) { skb->dev = dsa_conduit_find_user(dev, 0, port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } - if (pskb_trim_rcsum(skb, skb->len - len)) + if (pskb_trim_rcsum(skb, skb->len - len)) { + kfree_skb(skb); return NULL; + } dsa_default_offload_fwd_mark(skb); @@ -123,8 +127,10 @@ static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) struct ethhdr *hdr; u8 *tag; - if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { + kfree_skb(skb); return NULL; + } /* Tag encoding */ tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); @@ -141,8 +147,10 @@ static struct sk_buff *ksz8795_rcv(struct sk_buff *skb, struct net_device *dev) { u8 *tag; - if (skb_linearize(skb)) + if (skb_linearize(skb)) { + kfree_skb(skb); return NULL; + } tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; @@ -255,22 +263,24 @@ static struct sk_buff *ksz_defer_xmit(struct dsa_port *dp, struct sk_buff *skb) xmit_work_fn = tagger_data->xmit_work_fn; xmit_worker = priv->xmit_worker; - if (!xmit_work_fn || !xmit_worker) + if (!xmit_work_fn || !xmit_worker) { + kfree_skb(skb); return NULL; + } xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC); - if (!xmit_work) + if (!xmit_work) { + kfree_skb(skb); return NULL; + } kthread_init_work(&xmit_work->work, xmit_work_fn); - /* Increase refcount so the kfree_skb in dsa_user_xmit - * won't really free the packet. - */ xmit_work->dp = dp; xmit_work->skb = skb_get(skb); kthread_queue_work(xmit_worker, &xmit_work->work); + kfree_skb(skb); return NULL; } @@ -284,8 +294,10 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, __be16 *tag; u16 val; - if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { + kfree_skb(skb); return NULL; + } /* Tag encoding */ ksz_xmit_timestamp(dp, skb); @@ -310,8 +322,10 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev) unsigned int port; u8 *tag; - if (skb_linearize(skb)) + if (skb_linearize(skb)) { + kfree_skb(skb); return NULL; + } /* Tag decoding */ tag = skb_tail_pointer(skb) - KSZ_EGRESS_TAG_LEN; @@ -352,8 +366,10 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, struct ethhdr *hdr; u8 *tag; - if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { + kfree_skb(skb); return NULL; + } /* Tag encoding */ ksz_xmit_timestamp(dp, skb); @@ -418,8 +434,10 @@ static struct sk_buff *lan937x_xmit(struct sk_buff *skb, __be16 *tag; u16 val; - if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { + kfree_skb(skb); return NULL; + } ksz_xmit_timestamp(dp, skb); diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c index 258e5d7dc5ef..d1194696499a 100644 --- a/net/dsa/tag_lan9303.c +++ b/net/dsa/tag_lan9303.c @@ -85,6 +85,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev) if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN))) { dev_warn_ratelimited(&dev->dev, "Dropping packet, cannot pull\n"); + kfree_skb(skb); return NULL; } @@ -102,6 +103,7 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev) skb->dev = dsa_conduit_find_user(dev, 0, source_port); if (!skb->dev) { dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n"); + kfree_skb(skb); return NULL; } diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c index dea3eecaf093..c7dc7731675e 100644 --- a/net/dsa/tag_mtk.c +++ b/net/dsa/tag_mtk.c @@ -72,8 +72,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev) int port; __be16 *phdr; - if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) + if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN))) { + kfree_skb(skb); return NULL; + } phdr = dsa_etype_header_pos_rx(skb); hdr = ntohs(*phdr); @@ -87,8 +89,10 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev) port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK); skb->dev = dsa_conduit_find_user(dev, 0, port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } dsa_default_offload_fwd_mark(skb); diff --git a/net/dsa/tag_mxl-gsw1xx.c b/net/dsa/tag_mxl-gsw1xx.c index 60f7c445e656..4b1b6ef94196 100644 --- a/net/dsa/tag_mxl-gsw1xx.c +++ b/net/dsa/tag_mxl-gsw1xx.c @@ -73,6 +73,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb, if (unlikely(!pskb_may_pull(skb, GSW1XX_HEADER_LEN))) { dev_warn_ratelimited(&dev->dev, "Dropping packet, cannot pull SKB\n"); + kfree_skb(skb); return NULL; } @@ -81,6 +82,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb, if (unlikely(ntohs(gsw1xx_tag[0]) != ETH_P_MXLGSW)) { dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid special tag\n"); dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag); + kfree_skb(skb); return NULL; } @@ -90,6 +92,7 @@ static struct sk_buff *gsw1xx_tag_rcv(struct sk_buff *skb, if (!skb->dev) { dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n"); dev_warn_ratelimited(&dev->dev, "Tag: %8ph\n", gsw1xx_tag); + kfree_skb(skb); return NULL; } diff --git a/net/dsa/tag_mxl862xx.c b/net/dsa/tag_mxl862xx.c index 8daefeb8d49d..87b80ddf0946 100644 --- a/net/dsa/tag_mxl862xx.c +++ b/net/dsa/tag_mxl862xx.c @@ -64,6 +64,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb, if (unlikely(!pskb_may_pull(skb, MXL862_HEADER_LEN))) { dev_warn_ratelimited(&dev->dev, "Cannot pull SKB, packet dropped\n"); + kfree_skb(skb); return NULL; } @@ -73,6 +74,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb, dev_warn_ratelimited(&dev->dev, "Invalid special tag marker, packet dropped, tag: %8ph\n", mxl862_tag); + kfree_skb(skb); return NULL; } @@ -83,6 +85,7 @@ static struct sk_buff *mxl862_tag_rcv(struct sk_buff *skb, dev_warn_ratelimited(&dev->dev, "Invalid source port, packet dropped, tag: %8ph\n", mxl862_tag); + kfree_skb(skb); return NULL; } diff --git a/net/dsa/tag_netc.c b/net/dsa/tag_netc.c index ccedfe3a80b6..df72a61796ad 100644 --- a/net/dsa/tag_netc.c +++ b/net/dsa/tag_netc.c @@ -131,14 +131,13 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb, int type, subtype; if (unlikely(!pskb_may_pull(skb, NETC_TAG_MAX_LEN))) - return NULL; + goto err_free_skb; tag_cmn = dsa_etype_header_pos_rx(skb); if (ntohs(tag_cmn->tpid) != ETH_P_NXP_NETC) { dev_warn_ratelimited(&ndev->dev, "Unknown TPID 0x%04x\n", ntohs(tag_cmn->tpid)); - - return NULL; + goto err_free_skb; } if (tag_cmn->qos & NETC_TAG_QV) @@ -149,14 +148,13 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb, if (!sw_id) { dev_warn_ratelimited(&ndev->dev, "VEPA switch ID is not supported yet\n"); - - return NULL; + goto err_free_skb; } port = FIELD_GET(NETC_TAG_PORT, tag_cmn->switch_port); skb->dev = dsa_conduit_find_user(ndev, sw_id, port); if (!skb->dev) - return NULL; + goto err_free_skb; type = FIELD_GET(NETC_TAG_TYPE, tag_cmn->type); subtype = FIELD_GET(NETC_TAG_SUBTYPE, tag_cmn->type); @@ -165,11 +163,11 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb, } else if (type == NETC_TAG_TO_HOST) { /* Currently only subtype0 supported */ if (subtype != NETC_TAG_TH_SUBTYPE0) - return NULL; + goto err_free_skb; } else { dev_warn_ratelimited(&ndev->dev, "Unexpected tag type %d\n", type); - return NULL; + goto err_free_skb; } /* Remove Switch tag from the frame */ @@ -178,6 +176,10 @@ static struct sk_buff *netc_rcv(struct sk_buff *skb, dsa_strip_etype_header(skb, tag_len); return skb; + +err_free_skb: + kfree_skb(skb); + return NULL; } static void netc_flow_dissect(const struct sk_buff *skb, __be16 *proto, diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c index 3405def79c2d..d208c7322cd6 100644 --- a/net/dsa/tag_ocelot.c +++ b/net/dsa/tag_ocelot.c @@ -107,14 +107,16 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, ocelot_xfh_get_rew_val(extraction, &rew_val); skb->dev = dsa_conduit_find_user(netdev, 0, src_port); - if (!skb->dev) + if (!skb->dev) { /* The switch will reflect back some frames sent through * sockets opened on the bare DSA conduit. These will come back * with src_port equal to the index of the CPU port, for which * there is no user registered. So don't print any error * message here (ignore and drop those frames). */ + kfree_skb(skb); return NULL; + } dsa_default_offload_fwd_mark(skb); skb->priority = qos_class; diff --git a/net/dsa/tag_ocelot_8021q.c b/net/dsa/tag_ocelot_8021q.c index e89d9254e90a..f50f1cd83f16 100644 --- a/net/dsa/tag_ocelot_8021q.c +++ b/net/dsa/tag_ocelot_8021q.c @@ -33,30 +33,34 @@ static struct sk_buff *ocelot_defer_xmit(struct dsa_port *dp, xmit_work_fn = data->xmit_work_fn; xmit_worker = priv->xmit_worker; - if (!xmit_work_fn || !xmit_worker) + if (!xmit_work_fn || !xmit_worker) { + kfree_skb(skb); return NULL; + } /* PTP over IP packets need UDP checksumming. We may have inherited * NETIF_F_HW_CSUM from the DSA conduit, but these packets are not sent * through the DSA conduit, so calculate the checksum here. */ - if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { + kfree_skb(skb); return NULL; + } xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC); - if (!xmit_work) + if (!xmit_work) { + kfree_skb(skb); return NULL; + } /* Calls felix_port_deferred_xmit in felix.c */ kthread_init_work(&xmit_work->work, xmit_work_fn); - /* Increase refcount so the kfree_skb in dsa_user_xmit - * won't really free the packet. - */ xmit_work->dp = dp; xmit_work->skb = skb_get(skb); kthread_queue_work(xmit_worker, &xmit_work->work); + kfree_skb(skb); return NULL; } @@ -84,8 +88,10 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb, dsa_8021q_rcv(skb, &src_port, &switch_id, NULL, NULL); skb->dev = dsa_conduit_find_user(netdev, switch_id, src_port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } dsa_default_offload_fwd_mark(skb); diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c index 9e3b429e8b36..510792fbfa92 100644 --- a/net/dsa/tag_qca.c +++ b/net/dsa/tag_qca.c @@ -46,16 +46,20 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) tagger_data = ds->tagger_data; - if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) + if (unlikely(!pskb_may_pull(skb, QCA_HDR_LEN))) { + kfree_skb(skb); return NULL; + } phdr = dsa_etype_header_pos_rx(skb); hdr = ntohs(*phdr); /* Make sure the version is correct */ ver = FIELD_GET(QCA_HDR_RECV_VERSION, hdr); - if (unlikely(ver != QCA_HDR_VERSION)) + if (unlikely(ver != QCA_HDR_VERSION)) { + kfree_skb(skb); return NULL; + } /* Get pk type */ pk_type = FIELD_GET(QCA_HDR_RECV_TYPE, hdr); @@ -64,6 +68,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) if (pk_type == QCA_HDR_RECV_TYPE_RW_REG_ACK) { if (likely(tagger_data->rw_reg_ack_handler)) tagger_data->rw_reg_ack_handler(ds, skb); + kfree_skb(skb); return NULL; } @@ -71,6 +76,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) if (pk_type == QCA_HDR_RECV_TYPE_MIB) { if (likely(tagger_data->mib_autocast_handler)) tagger_data->mib_autocast_handler(ds, skb); + kfree_skb(skb); return NULL; } @@ -78,8 +84,10 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev) port = FIELD_GET(QCA_HDR_RECV_SOURCE_PORT, hdr); skb->dev = dsa_conduit_find_user(dev, 0, port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } /* Remove QCA tag and recalculate checksum */ skb_pull_rcsum(skb, QCA_HDR_LEN); diff --git a/net/dsa/tag_rtl4_a.c b/net/dsa/tag_rtl4_a.c index 3cc63eacfa03..590ea3b921c9 100644 --- a/net/dsa/tag_rtl4_a.c +++ b/net/dsa/tag_rtl4_a.c @@ -41,7 +41,7 @@ static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb, u16 out; /* Pad out to at least 60 bytes */ - if (unlikely(__skb_put_padto(skb, ETH_ZLEN, false))) + if (unlikely(eth_skb_pad(skb))) return NULL; netdev_dbg(dev, "add realtek tag to package to port %d\n", @@ -75,8 +75,10 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb, u8 prot; u8 port; - if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN))) + if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN))) { + kfree_skb(skb); return NULL; + } tag = dsa_etype_header_pos_rx(skb); p = (__be16 *)tag; @@ -92,6 +94,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb, prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f; if (prot != RTL4_A_PROTOCOL_RTL8366RB) { netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot); + kfree_skb(skb); return NULL; } port = protport & 0xff; @@ -99,6 +102,7 @@ static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb, skb->dev = dsa_conduit_find_user(dev, 0, port); if (!skb->dev) { netdev_dbg(dev, "could not find user for port %d\n", port); + kfree_skb(skb); return NULL; } diff --git a/net/dsa/tag_rtl8_4.c b/net/dsa/tag_rtl8_4.c index 852c6b88079a..4da3beebef75 100644 --- a/net/dsa/tag_rtl8_4.c +++ b/net/dsa/tag_rtl8_4.c @@ -143,8 +143,10 @@ static struct sk_buff *rtl8_4t_tag_xmit(struct sk_buff *skb, /* Calculate the checksum here if not done yet as trailing tags will * break either software or hardware based checksum */ - if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) { + kfree_skb(skb); return NULL; + } rtl8_4_write_tag(skb, dev, skb_put(skb, RTL8_4_TAG_LEN)); @@ -201,11 +203,15 @@ static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev, static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb, struct net_device *dev) { - if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN))) + if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN))) { + kfree_skb(skb); return NULL; + } - if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb)))) + if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb)))) { + kfree_skb(skb); return NULL; + } /* Remove tag and recalculate checksum */ skb_pull_rcsum(skb, RTL8_4_TAG_LEN); @@ -218,14 +224,20 @@ static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb, static struct sk_buff *rtl8_4t_tag_rcv(struct sk_buff *skb, struct net_device *dev) { - if (skb_linearize(skb)) + if (skb_linearize(skb)) { + kfree_skb(skb); return NULL; + } - if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN))) + if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN))) { + kfree_skb(skb); return NULL; + } - if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN)) + if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN)) { + kfree_skb(skb); return NULL; + } return skb; } diff --git a/net/dsa/tag_rzn1_a5psw.c b/net/dsa/tag_rzn1_a5psw.c index 10994b3470f6..734910156dc3 100644 --- a/net/dsa/tag_rzn1_a5psw.c +++ b/net/dsa/tag_rzn1_a5psw.c @@ -48,7 +48,7 @@ static struct sk_buff *a5psw_tag_xmit(struct sk_buff *skb, struct net_device *de * least 60 bytes otherwise they will be discarded when they enter the * switch port logic. */ - if (__skb_put_padto(skb, ETH_ZLEN, false)) + if (eth_skb_pad(skb)) return NULL; /* provide 'A5PSW_TAG_LEN' bytes additional space */ @@ -77,6 +77,7 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb, if (unlikely(!pskb_may_pull(skb, A5PSW_TAG_LEN))) { dev_warn_ratelimited(&dev->dev, "Dropping packet, cannot pull\n"); + kfree_skb(skb); return NULL; } @@ -84,14 +85,17 @@ static struct sk_buff *a5psw_tag_rcv(struct sk_buff *skb, if (tag->ctrl_tag != htons(ETH_P_DSA_A5PSW)) { dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid TAG marker\n"); + kfree_skb(skb); return NULL; } port = FIELD_GET(A5PSW_CTRL_DATA_PORT, ntohs(tag->ctrl_data)); skb->dev = dsa_conduit_find_user(dev, 0, port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } skb_pull_rcsum(skb, A5PSW_TAG_LEN); dsa_strip_etype_header(skb, A5PSW_TAG_LEN); diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c index de6d4ce8668b..bfe1f746f55b 100644 --- a/net/dsa/tag_sja1105.c +++ b/net/dsa/tag_sja1105.c @@ -149,19 +149,20 @@ static struct sk_buff *sja1105_defer_xmit(struct dsa_port *dp, xmit_work_fn = tagger_data->xmit_work_fn; xmit_worker = priv->xmit_worker; - if (!xmit_work_fn || !xmit_worker) + if (!xmit_work_fn || !xmit_worker) { + kfree_skb(skb); return NULL; + } xmit_work = kzalloc_obj(*xmit_work, GFP_ATOMIC); - if (!xmit_work) + if (!xmit_work) { + kfree_skb(skb); return NULL; + } kthread_init_work(&xmit_work->work, xmit_work_fn); - /* Increase refcount so the kfree_skb in dsa_user_xmit - * won't really free the packet. - */ xmit_work->dp = dp; - xmit_work->skb = skb_get(skb); + xmit_work->skb = skb; kthread_queue_work(xmit_worker, &xmit_work->work); @@ -401,10 +402,7 @@ static struct sk_buff kfree_skb(priv->stampable_skb); } - /* Hold a reference to avoid dsa_switch_rcv - * from freeing the skb. - */ - priv->stampable_skb = skb_get(skb); + priv->stampable_skb = skb; spin_unlock(&priv->meta_lock); /* Tell DSA we got nothing */ @@ -436,6 +434,7 @@ static struct sk_buff dev_err_ratelimited(ds->dev, "Unexpected meta frame\n"); spin_unlock(&priv->meta_lock); + kfree_skb(skb); return NULL; } @@ -443,6 +442,7 @@ static struct sk_buff dev_err_ratelimited(ds->dev, "Meta frame on wrong port\n"); spin_unlock(&priv->meta_lock); + kfree_skb(skb); return NULL; } @@ -501,18 +501,21 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb, /* Normal data plane traffic and link-local frames are tagged with * a tag_8021q VLAN which we have to strip */ - if (sja1105_skb_has_tag_8021q(skb)) + if (sja1105_skb_has_tag_8021q(skb)) { dsa_8021q_rcv(skb, &source_port, &switch_id, &vbid, &vid); - else if (source_port == -1 && switch_id == -1) + } else if (source_port == -1 && switch_id == -1) { /* Packets with no source information have no chance of * getting accepted, drop them straight away. */ + kfree_skb(skb); return NULL; + } skb->dev = dsa_tag_8021q_find_user(netdev, source_port, switch_id, vid, vbid); if (!skb->dev) { netdev_warn(netdev, "Couldn't decode source port\n"); + kfree_skb(skb); return NULL; } @@ -539,12 +542,15 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header) if (!ds) { net_err_ratelimited("%s: cannot find switch id %d\n", conduit->name, switch_id); + kfree_skb(skb); return NULL; } tagger_data = sja1105_tagger_data(ds); - if (!tagger_data->meta_tstamp_handler) + if (!tagger_data->meta_tstamp_handler) { + kfree_skb(skb); return NULL; + } for (i = 0; i <= n_ts; i++) { u8 ts_id, source_port, dir; @@ -562,6 +568,7 @@ static struct sk_buff *sja1110_rcv_meta(struct sk_buff *skb, u16 rx_header) } /* Discard the meta frame, we've consumed the timestamps it contained */ + kfree_skb(skb); return NULL; } @@ -572,8 +579,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb, { u16 rx_header; - if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN))) + if (unlikely(!pskb_may_pull(skb, SJA1110_HEADER_LEN))) { + kfree_skb(skb); return NULL; + } /* skb->data points to skb_mac_header(skb) + ETH_HLEN, which is exactly * what we need because the caller has checked the EtherType (which is @@ -609,8 +618,10 @@ static struct sk_buff *sja1110_rcv_inband_control_extension(struct sk_buff *skb, * padding and trailer we need to account for the fact that * skb->data points to skb_mac_header(skb) + ETH_HLEN. */ - if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN)) + if (pskb_trim_rcsum(skb, start_of_padding - ETH_HLEN)) { + kfree_skb(skb); return NULL; + } /* Trap-to-host frame, no timestamp trailer */ } else { *source_port = SJA1110_RX_HEADER_SRC_PORT(rx_header); @@ -653,6 +664,7 @@ static struct sk_buff *sja1110_rcv(struct sk_buff *skb, if (!skb->dev) { netdev_warn(netdev, "Couldn't decode source port\n"); + kfree_skb(skb); return NULL; } diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index 4dce24cfe6a7..49c802c10ca6 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -30,22 +30,30 @@ static struct sk_buff *trailer_rcv(struct sk_buff *skb, struct net_device *dev) u8 *trailer; int source_port; - if (skb_linearize(skb)) + if (skb_linearize(skb)) { + kfree_skb(skb); return NULL; + } trailer = skb_tail_pointer(skb) - 4; if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 || - (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) + (trailer[2] & 0xef) != 0x00 || trailer[3] != 0x00) { + kfree_skb(skb); return NULL; + } source_port = trailer[1] & 7; skb->dev = dsa_conduit_find_user(dev, 0, source_port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } - if (pskb_trim_rcsum(skb, skb->len - 4)) + if (pskb_trim_rcsum(skb, skb->len - 4)) { + kfree_skb(skb); return NULL; + } return skb; } diff --git a/net/dsa/tag_vsc73xx_8021q.c b/net/dsa/tag_vsc73xx_8021q.c index af121a9aff7f..f4736a1a7a0f 100644 --- a/net/dsa/tag_vsc73xx_8021q.c +++ b/net/dsa/tag_vsc73xx_8021q.c @@ -44,6 +44,7 @@ vsc73xx_rcv(struct sk_buff *skb, struct net_device *netdev) if (!skb->dev) { dev_warn_ratelimited(&netdev->dev, "Couldn't decode source port\n"); + kfree_skb(skb); return NULL; } diff --git a/net/dsa/tag_xrs700x.c b/net/dsa/tag_xrs700x.c index a05219f702c6..bb268020ee86 100644 --- a/net/dsa/tag_xrs700x.c +++ b/net/dsa/tag_xrs700x.c @@ -30,15 +30,21 @@ static struct sk_buff *xrs700x_rcv(struct sk_buff *skb, struct net_device *dev) source_port = ffs((int)trailer[0]) - 1; - if (source_port < 0) + if (source_port < 0) { + kfree_skb(skb); return NULL; + } skb->dev = dsa_conduit_find_user(dev, 0, source_port); - if (!skb->dev) + if (!skb->dev) { + kfree_skb(skb); return NULL; + } - if (pskb_trim_rcsum(skb, skb->len - 1)) + if (pskb_trim_rcsum(skb, skb->len - 1)) { + kfree_skb(skb); return NULL; + } /* Frame is forwarded by hardware, don't forward in software. */ dsa_default_offload_fwd_mark(skb); diff --git a/net/dsa/tag_yt921x.c b/net/dsa/tag_yt921x.c index f3ced99b1c85..294784ab6694 100644 --- a/net/dsa/tag_yt921x.c +++ b/net/dsa/tag_yt921x.c @@ -87,8 +87,10 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev) __be16 *tag; u16 rx; - if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN))) + if (unlikely(!pskb_may_pull(skb, YT921X_TAG_LEN))) { + kfree_skb(skb); return NULL; + } tag = dsa_etype_header_pos_rx(skb); @@ -96,6 +98,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev) dev_warn_ratelimited(&netdev->dev, "Unexpected EtherType 0x%04x\n", ntohs(tag[0])); + kfree_skb(skb); return NULL; } @@ -104,6 +107,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev) if (unlikely((rx & YT921X_TAG_PORT_EN) == 0)) { dev_warn_ratelimited(&netdev->dev, "Unexpected rx tag 0x%04x\n", rx); + kfree_skb(skb); return NULL; } @@ -112,6 +116,7 @@ yt921x_tag_rcv(struct sk_buff *skb, struct net_device *netdev) if (unlikely(!skb->dev)) { dev_warn_ratelimited(&netdev->dev, "Couldn't decode source port %u\n", port); + kfree_skb(skb); return NULL; } diff --git a/net/dsa/user.c b/net/dsa/user.c index 8704c1a3a5b7..072fa76972cc 100644 --- a/net/dsa/user.c +++ b/net/dsa/user.c @@ -935,13 +935,12 @@ static netdev_tx_t dsa_user_xmit(struct sk_buff *skb, struct net_device *dev) eth_skb_pad(skb); /* Transmit function may have to reallocate the original SKB, - * in which case it must have freed it. Only free it here on error. + * in which case it must have freed it. Taggers will drop the + * passed skb on error. */ nskb = p->xmit(skb, dev); - if (!nskb) { - kfree_skb(skb); + if (!nskb) return NETDEV_TX_OK; - } return dsa_enqueue_skb(nskb, dev); } diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c index a56bb79e15e0..e4ec60a33496 100644 --- a/net/ipv4/tcp_ao.c +++ b/net/ipv4/tcp_ao.c @@ -371,8 +371,9 @@ static void tcp_ao_key_free_rcu(struct rcu_head *head) kfree_sensitive(key); } -static void tcp_ao_info_free(struct tcp_ao_info *ao) +static void tcp_ao_info_free_rcu(struct rcu_head *head) { + struct tcp_ao_info *ao = container_of(head, struct tcp_ao_info, rcu); struct tcp_ao_key *key; struct hlist_node *n; @@ -411,7 +412,7 @@ void tcp_ao_destroy_sock(struct sock *sk, bool twsk) if (!twsk) tcp_ao_sk_omem_free(sk, ao); - tcp_ao_info_free(ao); + call_rcu(&ao->rcu, tcp_ao_info_free_rcu); } void tcp_ao_time_wait(struct tcp_timewait_sock *tcptw, struct tcp_sock *tp) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ec09f97cc9e6..209ef7522508 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1467,9 +1467,9 @@ void tcp_clear_md5_list(struct sock *sk) md5sig = rcu_dereference_protected(tp->md5sig_info, 1); hlist_for_each_entry_safe(key, n, &md5sig->head, node) { - hlist_del(&key->node); + hlist_del_rcu(&key->node); atomic_sub(sizeof(*key), &sk->sk_omem_alloc); - kfree(key); + kfree_rcu(key, rcu); } } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 00ec4b5900f2..d7c1444b5e30 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -4329,9 +4329,13 @@ int tcp_connect(struct sock *sk) if (needs_md5) { tcp_ao_destroy_sock(sk, false); } else if (needs_ao) { + struct tcp_md5sig_info *md5sig; + tcp_clear_md5_list(sk); - kfree(rcu_replace_pointer(tp->md5sig_info, NULL, - lockdep_sock_is_held(sk))); + md5sig = rcu_replace_pointer(tp->md5sig_info, NULL, + lockdep_sock_is_held(sk)); + kfree_rcu(md5sig, rcu); + static_branch_slow_dec_deferred(&tcp_md5_needed); } } #endif diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index fc95738ded76..a130cdfaebfb 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -636,12 +636,12 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) }; const struct nlmsghdr *nlh = cb->nlh; struct net *net = sock_net(skb->sk); - unsigned int e = 0, s_e; struct hlist_head *head; struct fib6_walker *w; struct fib6_table *tb; unsigned int h, s_h; int err = 0; + u32 s_id; rcu_read_lock(); if (cb->strict_check) { @@ -701,23 +701,22 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) } s_h = cb->args[0]; - s_e = cb->args[1]; + s_id = cb->args[1]; - for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { - e = 0; + for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_id = 0) { head = &net->ipv6.fib_table_hash[h]; hlist_for_each_entry_rcu(tb, head, tb6_hlist) { - if (e < s_e) - goto next; + if (s_id && tb->tb6_id != s_id) + continue; + + s_id = 0; + cb->args[1] = tb->tb6_id; err = fib6_dump_table(tb, skb, cb); if (err != 0) goto out; -next: - e++; } } out: - cb->args[1] = e; cb->args[0] = h; unlock: diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c index 1c3ad25700c4..62a7eb779202 100644 --- a/net/ipv6/seg6.c +++ b/net/ipv6/seg6.c @@ -29,6 +29,9 @@ bool seg6_validate_srh(struct ipv6_sr_hdr *srh, int len, bool reduced) int max_last_entry; int trailing; + if (len < sizeof(*srh)) + return false; + if (srh->type != IPV6_SRCRT_TYPE_4) return false; diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index a531b654b8d9..6cfad152d7d1 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1480,7 +1480,11 @@ ip_set_dump_done(struct netlink_callback *cb) struct ip_set_net *inst = (struct ip_set_net *)cb->args[IPSET_CB_NET]; ip_set_id_t index = (ip_set_id_t)cb->args[IPSET_CB_INDEX]; - struct ip_set *set = ip_set_ref_netlink(inst, index); + struct ip_set *set; + + rcu_read_lock(); + set = ip_set_ref_netlink(inst, index); + rcu_read_unlock(); if (set->variant->uref) set->variant->uref(set, cb, false); @@ -1686,7 +1690,9 @@ ip_set_dump_do(struct sk_buff *skb, struct netlink_callback *cb) release_refcount: /* If there was an error or set is done, release set */ if (ret || !cb->args[IPSET_CB_ARG0]) { + rcu_read_lock(); set = ip_set_ref_netlink(inst, index); + rcu_read_unlock(); if (set->variant->uref) set->variant->uref(set, cb, false); pr_debug("release set %s\n", set->name); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 38630c5e006f..7ae68d60586a 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -306,7 +306,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me) { struct nf_conntrack_expect *new; - new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC); + new = kmem_cache_zalloc(nf_ct_expect_cachep, GFP_ATOMIC); if (!new) return NULL; @@ -391,6 +391,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, #if IS_ENABLED(CONFIG_NF_NAT) memset(&exp->saved_addr, 0, sizeof(exp->saved_addr)); memset(&exp->saved_proto, 0, sizeof(exp->saved_proto)); + exp->dir = 0; #endif } EXPORT_SYMBOL_GPL(nf_ct_expect_init); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 4217715d42dc..31cbb1b55b9e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -3549,8 +3549,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, if (cda[CTA_EXPECT_FLAGS]) { exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS])); exp->flags &= ~NF_CT_EXPECT_USERSPACE; - } else { - exp->flags = 0; } if (cda[CTA_EXPECT_FN]) { const char *name = nla_data(cda[CTA_EXPECT_FN]); @@ -3562,8 +3560,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, goto err_out; } exp->expectfn = expfn->expectfn; - } else - exp->expectfn = NULL; + } exp->class = class; exp->master = ct; @@ -3583,12 +3580,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, exp, nf_ct_l3num(ct)); if (err < 0) goto err_out; -#if IS_ENABLED(CONFIG_NF_NAT) - } else { - memset(&exp->saved_addr, 0, sizeof(exp->saved_addr)); - memset(&exp->saved_proto, 0, sizeof(exp->saved_proto)); - exp->dir = 0; -#endif } return exp; err_out: diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 5ec3a4a4bbd7..f3f90a866338 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -956,7 +956,6 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, return NF_ACCEPT; saddr = &ct->tuplehash[!dir].tuple.src.u3; } else if (sip_external_media) { - struct net_device *dev = skb_dst(skb)->dev; struct dst_entry *dst = NULL; struct flowi fl; @@ -978,7 +977,11 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, * through the same interface as the signalling peer. */ if (dst) { - bool external_media = (dst->dev == dev); + const struct dst_entry *this_dst = skb_dst(skb); + bool external_media = false; + + if (this_dst && dst->dev == this_dst->dev) + external_media = true; dst_release(dst); if (external_media) diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index f1460b683d7a..2cbcca9110db 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -163,6 +163,8 @@ nfnl_cthelper_expect_policy(struct nf_conntrack_expect_policy *expect_policy, tb[NFCTH_POLICY_NAME], NF_CT_HELPER_NAME_LEN); expect_policy->max_expected = ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX])); + if (!expect_policy->max_expected) + expect_policy->max_expected = NF_CT_EXPECT_MAX_CNT; if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT) return -EINVAL; diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 80ca077b81bd..35d4c6c628ff 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -1184,6 +1184,173 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) return err; } +static bool nfqnl_validate_ipopts(const struct iphdr *iph_new, + const struct nf_queue_entry *e) +{ + const struct iphdr *iph_orig = ip_hdr(e->skb); + unsigned int ihl = iph_new->ihl * 4; + + if (iph_new->ihl != iph_orig->ihl) + return false; + if (ihl == sizeof(*iph_orig)) + return true; + + return memcmp(iph_new + 1, ip_hdr(e->skb) + 1, ihl - sizeof(*iph_orig)) == 0; +} + +static bool nfqnl_validate_ip4(const struct iphdr *iph, unsigned int data_len, + const struct nf_queue_entry *e) +{ + unsigned int ihl; + + if (data_len < sizeof(*iph)) + return false; + + ihl = iph->ihl * 4u; + if (ihl < sizeof(*iph) || data_len < ihl) + return false; + + if (iph->version != 4 || + ((iph->frag_off ^ ip_hdr(e->skb)->frag_off) & ~htons(IP_DF)) != 0) + return false; + + /* BIG TCP won't work; netlink attr len is u16 */ + if (ntohs(iph->tot_len) != data_len) + return false; + + /* support for ipopts mangling would require + * recompile + skb transport header update. + */ + return nfqnl_validate_ipopts(iph, e); +} + +static bool nfqnl_validate_one_exthdr(const u8 *data, + unsigned int data_len, + const struct nf_queue_entry *e, + int start, int hdrlen) +{ + u16 octets; + + if (data_len < hdrlen || hdrlen < 2) + return false; + + while (hdrlen > 0) { + if (data_len < sizeof(octets)) + return false; + data_len -= sizeof(octets); + + if (skb_copy_bits(e->skb, start, &octets, sizeof(octets))) + return false; + + if (hdrlen < sizeof(octets)) + return false; + + hdrlen -= sizeof(octets); + if (memcmp(data, &octets, sizeof(octets))) + return false; + + start += sizeof(octets); + data += sizeof(octets); + } + + return true; +} + +static bool nfqnl_validate_exthdr(const struct ipv6hdr *ip6_new, + unsigned int data_len, + const struct nf_queue_entry *e) +{ + const struct ipv6hdr *ip6_orig = ipv6_hdr(e->skb); + int exthdr_cnt = 0, start = sizeof(*ip6_orig); + const u8 *data = (const u8 *)ip6_new; + u8 orig_nexthdr = ip6_orig->nexthdr; + u8 new_nexthdr = ip6_new->nexthdr; + + if (new_nexthdr != orig_nexthdr) + return false; + + data += sizeof(*ip6_new); + data_len -= sizeof(*ip6_new); + + while (ipv6_ext_hdr(orig_nexthdr)) { + const struct ipv6_opt_hdr *hp; + struct ipv6_opt_hdr _hdr; + int hdrlen; + + if (orig_nexthdr == NEXTHDR_NONE) + return true; + + if (unlikely(exthdr_cnt++ >= IP6_MAX_EXT_HDRS_CNT)) + return false; + + hp = skb_header_pointer(e->skb, start, sizeof(_hdr), &_hdr); + if (!hp) + return false; + + switch (orig_nexthdr) { + case NEXTHDR_FRAGMENT: + hdrlen = sizeof(struct frag_hdr); + break; + case NEXTHDR_AUTH: + hdrlen = ipv6_authlen(hp); + break; + default: + hdrlen = ipv6_optlen(hp); + break; + } + + if (!nfqnl_validate_one_exthdr(data, data_len, e, + start, hdrlen)) + return false; + + orig_nexthdr = hp->nexthdr; + hp = (const void *)data; + new_nexthdr = hp->nexthdr; + + if (new_nexthdr != orig_nexthdr) + return false; + + data_len -= hdrlen; + start += hdrlen; + data += hdrlen; + } + + return true; +} + +static bool nfqnl_validate_ip6(const struct ipv6hdr *ip6, unsigned int data_len, + const struct nf_queue_entry *e) +{ + if (data_len < sizeof(*ip6)) + return false; + + /* BIG TCP/jumbograms won't work; netlink attr len is u16 */ + if (ntohs(ip6->payload_len) != data_len - sizeof(*ip6)) + return false; + + if (ip6->version != 6) + return false; + + return nfqnl_validate_exthdr(ip6, data_len, e); +} + +static bool nfqnl_validate_write(const void *data, unsigned int data_len, + const struct nf_queue_entry *e) +{ + switch (e->state.pf) { + case NFPROTO_IPV4: + return nfqnl_validate_ip4(data, data_len, e); + case NFPROTO_IPV6: + return nfqnl_validate_ip6(data, data_len, e) && + !(IP6CB(e->skb)->flags & IP6SKB_JUMBOGRAM); + case NFPROTO_BRIDGE: + /* No write support. Bridge is dubious: userspace doesn't even see L2 header */ + return false; + } + + return false; +} + static int nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int diff) { @@ -1192,6 +1359,9 @@ nfqnl_mangle(void *data, unsigned int data_len, struct nf_queue_entry *e, int di if (e->state.net->user_ns != &init_user_ns) return -EPERM; + if (!nfqnl_validate_write(data, data_len, e)) + return -EINVAL; + if (diff < 0) { unsigned int min_len = skb_transport_offset(e->skb); diff --git a/net/netfilter/nft_fib.c b/net/netfilter/nft_fib.c index e048f05694cd..89555380f1c5 100644 --- a/net/netfilter/nft_fib.c +++ b/net/netfilter/nft_fib.c @@ -31,6 +31,15 @@ int nft_fib_validate(const struct nft_ctx *ctx, const struct nft_expr *expr) const struct nft_fib *priv = nft_expr_priv(expr); unsigned int hooks; + switch (ctx->family) { + case NFPROTO_IPV4: + case NFPROTO_IPV6: + case NFPROTO_INET: + break; + default: + return -EOPNOTSUPP; + } + switch (priv->result) { case NFT_FIB_RESULT_OIF: case NFT_FIB_RESULT_OIFNAME: diff --git a/net/netfilter/nft_fib_netdev.c b/net/netfilter/nft_fib_netdev.c index 3f3478abd845..5774a7544027 100644 --- a/net/netfilter/nft_fib_netdev.c +++ b/net/netfilter/nft_fib_netdev.c @@ -50,6 +50,33 @@ static void nft_fib_netdev_eval(const struct nft_expr *expr, regs->verdict.code = NFT_BREAK; } +static int nft_fib_netdev_validate(const struct nft_ctx *ctx, + const struct nft_expr *expr) +{ + const struct nft_fib *priv = nft_expr_priv(expr); + unsigned int hooks; + + switch (priv->result) { + case NFT_FIB_RESULT_OIF: + case NFT_FIB_RESULT_OIFNAME: + hooks = (1 << NF_NETDEV_INGRESS); + break; + case NFT_FIB_RESULT_ADDRTYPE: + if (priv->flags & NFTA_FIB_F_IIF) + hooks = (1 << NF_NETDEV_INGRESS); + else if (priv->flags & NFTA_FIB_F_OIF) + hooks = (1 << NF_NETDEV_EGRESS); + else + hooks = (1 << NF_NETDEV_INGRESS) | + (1 << NF_NETDEV_EGRESS); + break; + default: + return -EINVAL; + } + + return nft_chain_validate_hooks(ctx->chain, hooks); +} + static struct nft_expr_type nft_fib_netdev_type; static const struct nft_expr_ops nft_fib_netdev_ops = { .type = &nft_fib_netdev_type, @@ -57,7 +84,7 @@ static const struct nft_expr_ops nft_fib_netdev_ops = { .eval = nft_fib_netdev_eval, .init = nft_fib_init, .dump = nft_fib_dump, - .validate = nft_fib_validate, + .validate = nft_fib_netdev_validate, }; static struct nft_expr_type nft_fib_netdev_type __read_mostly = { diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c index 345eff140d56..391539a1ceaa 100644 --- a/net/netfilter/nft_payload.c +++ b/net/netfilter/nft_payload.c @@ -834,6 +834,249 @@ nft_payload_set_vlan(const u32 *src, struct sk_buff *skb, u16 offset, u8 len, return true; } +/* Ingress is very early, before l3 protocol handlers. + * There should be no in-tree code that trusts l3/l4 headers + * between ingress and NF_INET_PRE_ROUTING hooks. + */ +static bool nft_in_ingress(const struct nf_hook_state *s) +{ + return s->pf == NFPROTO_NETDEV && s->hook == NF_NETDEV_INGRESS; +} + +static bool nft_nh_write_ok_ip4(const struct nft_pktinfo *pkt, + const struct nft_payload_set *priv, + const u32 *src) +{ + unsigned int offset = priv->offset + skb_network_offset(pkt->skb); + const u8 *new_octets = (const u8 *)src; + u8 old_octet; + + switch (priv->offset) { + case 0: /* csum fixups does expand dscp/tos store to 2 bytes. + * make sure ihl/version remain unchanged. + */ + if (skb_copy_bits(pkt->skb, offset, &old_octet, sizeof(old_octet))) + return false; + + return priv->len == 2 && + *new_octets == old_octet; + case offsetof(struct iphdr, tos): + return priv->len == 1; + case offsetof(struct iphdr, id): + return priv->len == 2; + case offsetof(struct iphdr, ttl): + if (priv->len == 1) + return true; + + if (priv->len != 2) + return false; + + /* same, csum fixup does expand ttl store to two bytes. + * check protocol is not altered. + */ + if (skb_copy_bits(pkt->skb, offset + 1, &old_octet, sizeof(old_octet))) + return false; + + return new_octets[1] == old_octet; + case offsetof(struct iphdr, check): + return priv->len <= 2 + 4 + 4; + case offsetof(struct iphdr, saddr): + return priv->len <= 4 + 4; + case offsetof(struct iphdr, daddr): + return priv->len <= 4; + } + + return false; +} + +static bool nft_nh_write_ok_ip6(const struct nft_pktinfo *pkt, + const struct nft_payload_set *priv, + const u32 *src) +{ + const struct ipv6hdr *ih = (const void *)src; + + switch (priv->offset) { + case 0: /* store to dscp must not alter ip6 version */ + return priv->len <= 4 && ih->version == 6; + case 2: + return priv->len <= 2; + case offsetof(struct ipv6hdr, hop_limit): + return priv->len == 1; + case offsetof(struct ipv6hdr, saddr): + return priv->len <= 16 + 16; + case offsetof(struct ipv6hdr, daddr): + return priv->len <= 16; + } + + return false; +} + +static bool nft_nh_write_ok_arp(const struct nft_payload_set *priv) +{ + /* Variable size for standard ethernet arp */ + const unsigned int eth_ip = 2 * (ETH_ALEN + 4); + unsigned int offset = priv->offset; + + switch (offset) { + case offsetof(struct arphdr, ar_op): + return priv->len == 2; + default: + break; + } + + /* permit writes post fixed arp header size. offset + len are + * checked vs skb size via skb_ensure_writable. + */ + return offset >= sizeof(struct arphdr) && priv->len <= eth_ip; +} + +static bool nft_nh_write_ok_netdev(const struct nft_pktinfo *pkt, + const struct nft_payload_set *priv, + const u32 *src) +{ +#ifdef CONFIG_NF_TABLES_NETDEV + switch (pkt->skb->protocol) { + case htons(ETH_P_ARP): + return nft_nh_write_ok_arp(priv); + case htons(ETH_P_IP): + return nft_nh_write_ok_ip4(pkt, priv, src); + case htons(ETH_P_IPV6): + return nft_nh_write_ok_ip6(pkt, priv, src); + } +#endif + /* default to false for now, relax later in case we have + * use-cases that need inner header manipulation for + * encapsulated traffic like vlan or PPPoE. + */ + return false; +} + +static bool nft_nh_write_ok_bridge(const struct nft_pktinfo *pkt, + const struct nft_payload_set *priv, + const u32 *src) +{ +#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE) + switch (pkt->ethertype) { + case htons(ETH_P_ARP): + return nft_nh_write_ok_arp(priv); + case htons(ETH_P_IP): + return nft_nh_write_ok_ip4(pkt, priv, src); + case htons(ETH_P_IPV6): + return nft_nh_write_ok_ip6(pkt, priv, src); + } +#endif + /* see nft_nh_write_ok_netdev: default to false */ + return false; +} + +static bool nft_nh_write_ok(const struct nft_pktinfo *pkt, + const struct nft_payload_set *priv, + const u32 *src) +{ + switch (pkt->state->pf) { + case NFPROTO_ARP: + return nft_nh_write_ok_arp(priv); + case NFPROTO_BRIDGE: + return nft_nh_write_ok_bridge(pkt, priv, src); + case NFPROTO_IPV4: + return nft_nh_write_ok_ip4(pkt, priv, src); + case NFPROTO_IPV6: + return nft_nh_write_ok_ip6(pkt, priv, src); + case NFPROTO_NETDEV: + if (pkt->state->hook == NF_NETDEV_INGRESS) + return true; + return nft_nh_write_ok_netdev(pkt, priv, src); + } + + return false; +} + +/* check linklayer modifications don't spill into network header. */ +static bool nft_ll_write_ok(const struct nft_pktinfo *pkt, int offset) +{ + if (nft_in_ingress(pkt->state)) + return true; + + return offset <= skb_network_offset(pkt->skb); +} + +static bool nft_payload_validate_inet_csum_offset(const struct nft_ctx *ctx, + const struct nft_payload_set *priv) +{ + switch (priv->base) { + case NFT_PAYLOAD_LL_HEADER: + break; + case NFT_PAYLOAD_NETWORK_HEADER: + if (ctx->family == NFPROTO_IPV4) { + if (offsetof(struct iphdr, check) == priv->csum_offset) + return true; + + return false; + } + return true; /* run time validation required */ + case NFT_PAYLOAD_TRANSPORT_HEADER: + if (priv->csum_flags) /* makes no sense, asks for "re-update" of L4 checksum */ + return false; + + /* no further check here; offset can't be negative so bogus + * offsets can corrupt L4 or payload but not l3 headers. + * We already allow arbitrary l4/inner payload writes. + */ + return true; + case NFT_PAYLOAD_INNER_HEADER: + return true; + case NFT_PAYLOAD_TUN_HEADER: + break; + } + + return false; +} + +/* do not allow arbitrary network header mangling via bogus csum_off. + * We only support ipv4. Only NFPROTO_IPV4 can be checked from control + * plane. + */ +static bool nft_payload_csum_nh_write_ok(const struct nft_payload_set *priv, + const struct nft_pktinfo *pkt) +{ + switch (pkt->state->pf) { + case NFPROTO_IPV4: + /* Warning: NFPROTO_INET was not checked; we can't return true here. */ + return priv->csum_offset == offsetof(struct iphdr, check); + case NFPROTO_IPV6: + return false; + case NFPROTO_BRIDGE: + return pkt->ethertype == htons(ETH_P_IP) && + priv->csum_offset == offsetof(struct iphdr, check); + case NFPROTO_NETDEV: + return pkt->skb->protocol == htons(ETH_P_IP) && + priv->csum_offset == offsetof(struct iphdr, check); + } + + return false; +} + +static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt, + const struct nft_payload_set *priv) +{ + switch (priv->base) { + case NFT_PAYLOAD_LL_HEADER: + break; + case NFT_PAYLOAD_NETWORK_HEADER: + return nft_payload_csum_nh_write_ok(priv, pkt); + case NFT_PAYLOAD_TRANSPORT_HEADER: + case NFT_PAYLOAD_INNER_HEADER: + /* neither offsets are validated, offsets cannot be + * negative so real l3 headers cannot be mangled. + */ + return true; + case NFT_PAYLOAD_TUN_HEADER: + break; + } + + return false; +} + static void nft_payload_set_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) @@ -861,8 +1104,12 @@ static void nft_payload_set_eval(const struct nft_expr *expr, } offset = skb_mac_header(skb) - skb->data - vlan_hlen; + if (!nft_ll_write_ok(pkt, priv->len + priv->offset + offset)) + goto err; break; case NFT_PAYLOAD_NETWORK_HEADER: + if (!nft_nh_write_ok(pkt, priv, src)) + goto err; offset = skb_network_offset(skb); break; case NFT_PAYLOAD_TRANSPORT_HEADER: @@ -894,6 +1141,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr, tsum = csum_partial(src, priv->len, 0); if (priv->csum_type == NFT_PAYLOAD_CSUM_INET && + nft_payload_csum_write_ok(pkt, priv) && nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset)) goto err; @@ -960,7 +1208,26 @@ static int nft_payload_set_init(const struct nft_ctx *ctx, switch (csum_type) { case NFT_PAYLOAD_CSUM_NONE: + if (priv->csum_offset) /* nonsensical */ + return -EINVAL; + + if (priv->csum_flags == 0) + break; + + /* Userspace requests L4 checksum update, e.g.: + * - IPv6 stateless NAT (no l3 csum) + * - transport header mangling + * - inner data mangling + */ + if (priv->base == NFT_PAYLOAD_NETWORK_HEADER || + priv->base == NFT_PAYLOAD_TRANSPORT_HEADER || + priv->base == NFT_PAYLOAD_INNER_HEADER) + break; + + return -EINVAL; case NFT_PAYLOAD_CSUM_INET: + if (!nft_payload_validate_inet_csum_offset(ctx, priv)) + return -EINVAL; break; case NFT_PAYLOAD_CSUM_SCTP: if (priv->base != NFT_PAYLOAD_TRANSPORT_HEADER) @@ -968,6 +1235,9 @@ static int nft_payload_set_init(const struct nft_ctx *ctx, if (priv->csum_offset != offsetof(struct sctphdr, checksum)) return -EINVAL; + + if (priv->csum_flags) + return -EINVAL; break; default: return -EOPNOTSUPP; diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c index 706c78853f24..978bb0c01106 100644 --- a/net/netfilter/nft_set_pipapo.c +++ b/net/netfilter/nft_set_pipapo.c @@ -342,6 +342,8 @@ #include "nft_set_pipapo_avx2.h" #include "nft_set_pipapo.h" +static void nft_pipapo_abort(const struct nft_set *set); + /** * pipapo_refill() - For each set bit, set bits from selected mapping table item * @map: Bitmap to be scanned for set bits @@ -1296,7 +1298,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, const u8 *start_p, *end_p; int i, bsize_max, err = 0; - if (!m) + if (!m || m->state == NFT_PIPAPO_CLONE_ERR) return -ENOMEM; if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END)) @@ -1367,8 +1369,10 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, else ret = pipapo_expand(f, start, end, f->groups * f->bb); - if (ret < 0) - return ret; + if (ret < 0) { + err = ret; + goto abort; + } if (f->bsize > bsize_max) bsize_max = f->bsize; @@ -1384,7 +1388,7 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, err = pipapo_realloc_scratch(m, bsize_max); if (err) - return err; + goto abort; m->bsize_max = bsize_max; } else { @@ -1396,7 +1400,26 @@ static int nft_pipapo_insert(const struct net *net, const struct nft_set *set, pipapo_map(m, rulemap, e); + m->state = NFT_PIPAPO_CLONE_MOD; return 0; +abort: + DEBUG_NET_WARN_ON_ONCE(m->state == NFT_PIPAPO_CLONE_ERR); + + /* Two rollback cases: + * 1) no previous changes. nft_pipapo_abort is not + * guaranteed to be invoked (there might be no further + * add/delete requests coming after this). + * + * 2) we had previous changes: there are transaction + * records pointing to this set. Leave the rollback to + * the transaction handling. + */ + if (m->state == NFT_PIPAPO_CLONE_NEW) + nft_pipapo_abort(set); /* releases m */ + else + m->state = NFT_PIPAPO_CLONE_ERR; + + return err; } /** @@ -1473,6 +1496,7 @@ static struct nft_pipapo_match *pipapo_clone(struct nft_pipapo_match *old) dst++; } + new->state = NFT_PIPAPO_CLONE_NEW; return new; out_mt: @@ -1896,7 +1920,7 @@ nft_pipapo_deactivate(const struct net *net, const struct nft_set *set, /* removal must occur on priv->clone, if we are low on memory * we have no choice and must fail the removal request. */ - if (!m) + if (!m || m->state == NFT_PIPAPO_CLONE_ERR) return NULL; e = pipapo_get(m, (const u8 *)elem->key.val.data, diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h index b82abb03576e..a19e980d06ef 100644 --- a/net/netfilter/nft_set_pipapo.h +++ b/net/netfilter/nft_set_pipapo.h @@ -131,9 +131,16 @@ struct nft_pipapo_scratch { unsigned long __map[]; }; +enum nft_pipapo_clone_state { + NFT_PIPAPO_CLONE_NEW, + NFT_PIPAPO_CLONE_MOD, + NFT_PIPAPO_CLONE_ERR, +}; + /** * struct nft_pipapo_match - Data used for lookup and matching * @field_count: Amount of fields in set + * @state: add/delete state; used from control plane * @bsize_max: Maximum lookup table bucket size of all fields, in longs * @scratch: Preallocated per-CPU maps for partial matching results * @rcu: Matching data is swapped on commits @@ -141,6 +148,7 @@ struct nft_pipapo_scratch { */ struct nft_pipapo_match { u8 field_count; + enum nft_pipapo_clone_state state:8; unsigned int bsize_max; struct nft_pipapo_scratch * __percpu *scratch; struct rcu_head rcu; diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index 80e341d2f8a4..3990da1a65dc 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c index cf2dcec6ce5a..9c5b695dba7c 100644 --- a/net/rfkill/rfkill-gpio.c +++ b/net/rfkill/rfkill-gpio.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 58a074651176..09d46e195e33 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -44,7 +44,7 @@ TC_INDIRECT_SCOPE int tcf_bpf_act(struct sk_buff *skb, tcf_lastuse_update(&prog->tcf_tm); bstats_update(this_cpu_ptr(prog->common.cpu_bstats), skb); - filter = rcu_dereference(prog->filter); + filter = rcu_dereference_bh(prog->filter); if (at_ingress) { __skb_push(skb, skb->mac_len); filter_res = bpf_prog_run_data_pointers(filter, skb); diff --git a/net/sched/sch_dualpi2.c b/net/sched/sch_dualpi2.c index 5434df6ca8ef..27088760eff4 100644 --- a/net/sched/sch_dualpi2.c +++ b/net/sched/sch_dualpi2.c @@ -346,6 +346,8 @@ static int dualpi2_skb_classify(struct dualpi2_sched_data *q, struct tcf_proto *fl; int result; + cb->classified = DUALPI2_C_CLASSIC; + dualpi2_read_ect(skb); if (cb->ect & q->ecn_mask) { cb->classified = DUALPI2_C_L4S; @@ -359,10 +361,8 @@ static int dualpi2_skb_classify(struct dualpi2_sched_data *q, } fl = rcu_dereference_bh(q->tcf_filters); - if (!fl) { - cb->classified = DUALPI2_C_CLASSIC; + if (!fl) return NET_XMIT_SUCCESS; - } result = tcf_classify(skb, NULL, fl, &res, false); if (result >= 0) { diff --git a/net/sched/sch_hhf.c b/net/sched/sch_hhf.c index 1e25b75daae2..d85cb0263b67 100644 --- a/net/sched/sch_hhf.c +++ b/net/sched/sch_hhf.c @@ -462,12 +462,39 @@ static struct sk_buff *hhf_dequeue(struct Qdisc *sch) return skb; } +static void hhf_reset_classifier(struct hhf_sched_data *q) +{ + int i; + + if (!q->hh_flows) + return; + + for (i = 0; i < HH_FLOWS_CNT; i++) { + struct hh_flow_state *flow, *next; + struct list_head *head = &q->hh_flows[i]; + + list_for_each_entry_safe(flow, next, head, flowchain) { + list_del(&flow->flowchain); + kfree(flow); + } + } + WRITE_ONCE(q->hh_flows_current_cnt, 0); + + for (i = 0; i < HHF_ARRAYS_CNT; i++) { + if (q->hhf_valid_bits[i]) + bitmap_zero(q->hhf_valid_bits[i], HHF_ARRAYS_LEN); + } + q->hhf_arrays_reset_timestamp = hhf_time_stamp(); +} + static void hhf_reset(struct Qdisc *sch) { + struct hhf_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; while ((skb = hhf_dequeue(sch)) != NULL) rtnl_kfree_skbs(skb, skb); + hhf_reset_classifier(q); } static void hhf_destroy(struct Qdisc *sch) diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 4e465d11e3d7..a467dd122369 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -103,7 +103,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch) if (!netif_xmit_stopped( netdev_get_tx_queue(qdisc_dev(sch), q->curband))) { qdisc = q->queues[q->curband]; - skb = qdisc->dequeue(qdisc); + skb = qdisc_dequeue_peeked(qdisc); if (skb) { qdisc_bstats_update(sch, skb); qdisc_qlen_dec(sch); diff --git a/net/sched/sch_taprio.c b/net/sched/sch_taprio.c index 558987d9b977..299234a5f0fe 100644 --- a/net/sched/sch_taprio.c +++ b/net/sched/sch_taprio.c @@ -749,7 +749,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq, return NULL; skip_peek_checks: - skb = child->ops->dequeue(child); + skb = qdisc_dequeue_peeked(child); if (unlikely(!skb)) return NULL; diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index e7bbc9e5174d..24ba31f8c828 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -52,7 +52,8 @@ struct teql_master { struct Qdisc_ops qops; struct net_device *dev; - struct Qdisc *slaves; + struct Qdisc __rcu *slaves; + spinlock_t slaves_lock; /* serializes writes to ->slaves */ struct list_head master_list; unsigned long tx_bytes; unsigned long tx_packets; @@ -61,7 +62,7 @@ struct teql_master { }; struct teql_sched_data { - struct Qdisc *next; + struct Qdisc __rcu *next; struct teql_master *m; struct sk_buff_head q; }; @@ -101,7 +102,9 @@ teql_dequeue(struct Qdisc *sch) if (skb == NULL) { struct net_device *m = qdisc_dev(q); if (m) { - dat->m->slaves = sch; + spin_lock_bh(&dat->m->slaves_lock); + rcu_assign_pointer(dat->m->slaves, sch); + spin_unlock_bh(&dat->m->slaves_lock); netif_wake_queue(m); } } else { @@ -132,34 +135,49 @@ teql_destroy(struct Qdisc *sch) struct Qdisc *q, *prev; struct teql_sched_data *dat = qdisc_priv(sch); struct teql_master *master = dat->m; + struct netdev_queue *txq = NULL; + bool reset_master_queue = false; if (!master) return; - prev = master->slaves; + spin_lock_bh(&master->slaves_lock); + prev = rcu_dereference_protected(master->slaves, + lockdep_is_held(&master->slaves_lock)); if (prev) { do { - q = NEXT_SLAVE(prev); - if (q == sch) { - NEXT_SLAVE(prev) = NEXT_SLAVE(q); - if (q == master->slaves) { - master->slaves = NEXT_SLAVE(q); - if (q == master->slaves) { - struct netdev_queue *txq; + struct Qdisc *head, *next; - txq = netdev_get_tx_queue(master->dev, 0); - master->slaves = NULL; - - dev_reset_queue(master->dev, - txq, NULL); - } - } - skb_queue_purge(&dat->q); - break; + q = rcu_dereference_protected(NEXT_SLAVE(prev), + lockdep_is_held(&master->slaves_lock)); + if (q != sch) { + prev = q; + continue; } - } while ((prev = q) != master->slaves); + next = rcu_dereference_protected(NEXT_SLAVE(q), + lockdep_is_held(&master->slaves_lock)); + rcu_assign_pointer(NEXT_SLAVE(prev), next); + + head = rcu_dereference_protected(master->slaves, + lockdep_is_held(&master->slaves_lock)); + if (q == head) { + rcu_assign_pointer(master->slaves, next); + if (q == next) { + txq = netdev_get_tx_queue(master->dev, 0); + rcu_assign_pointer(master->slaves, NULL); + reset_master_queue = true; + } + } + skb_queue_purge(&dat->q); + break; + } while (prev != rcu_dereference_protected(master->slaves, + lockdep_is_held(&master->slaves_lock))); } + spin_unlock_bh(&master->slaves_lock); + + if (reset_master_queue) + dev_reset_queue(master->dev, txq, NULL); } static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, @@ -168,6 +186,7 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, struct net_device *dev = qdisc_dev(sch); struct teql_master *m = (struct teql_master *)sch->ops; struct teql_sched_data *q = qdisc_priv(sch); + struct Qdisc *first; if (dev->hard_header_len > m->dev->hard_header_len) return -EINVAL; @@ -184,7 +203,9 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, skb_queue_head_init(&q->q); - if (m->slaves) { + spin_lock_bh(&m->slaves_lock); + first = rcu_dereference_protected(m->slaves, lockdep_is_held(&m->slaves_lock)); + if (first) { if (m->dev->flags & IFF_UP) { if ((m->dev->flags & IFF_POINTOPOINT && !(dev->flags & IFF_POINTOPOINT)) || @@ -192,8 +213,10 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, !(dev->flags & IFF_BROADCAST)) || (m->dev->flags & IFF_MULTICAST && !(dev->flags & IFF_MULTICAST)) || - dev->mtu < m->dev->mtu) + dev->mtu < m->dev->mtu) { + spin_unlock_bh(&m->slaves_lock); return -EINVAL; + } } else { if (!(dev->flags&IFF_POINTOPOINT)) m->dev->flags &= ~IFF_POINTOPOINT; @@ -204,14 +227,17 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt, if (dev->mtu < m->dev->mtu) m->dev->mtu = dev->mtu; } - q->next = NEXT_SLAVE(m->slaves); - NEXT_SLAVE(m->slaves) = sch; + rcu_assign_pointer(q->next, + rcu_dereference_protected(NEXT_SLAVE(first), + lockdep_is_held(&m->slaves_lock))); + rcu_assign_pointer(NEXT_SLAVE(first), sch); } else { - q->next = sch; - m->slaves = sch; + rcu_assign_pointer(q->next, sch); + rcu_assign_pointer(m->slaves, sch); m->dev->mtu = dev->mtu; m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK); } + spin_unlock_bh(&m->slaves_lock); return 0; } @@ -285,7 +311,9 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) int subq = skb_get_queue_mapping(skb); struct sk_buff *skb_res = NULL; - start = master->slaves; + rcu_read_lock_bh(); + + start = rcu_dereference_bh(master->slaves); restart: nores = 0; @@ -317,10 +345,17 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) netdev_start_xmit(skb, slave, slave_txq, false) == NETDEV_TX_OK) { __netif_tx_unlock(slave_txq); - master->slaves = NEXT_SLAVE(q); + spin_lock_bh(&master->slaves_lock); + if (rcu_dereference_protected(master->slaves, + lockdep_is_held(&master->slaves_lock)) == q) + rcu_assign_pointer(master->slaves, + rcu_dereference_protected(NEXT_SLAVE(q), + lockdep_is_held(&master->slaves_lock))); + spin_unlock_bh(&master->slaves_lock); netif_wake_queue(dev); master->tx_packets++; master->tx_bytes += length; + rcu_read_unlock_bh(); return NETDEV_TX_OK; } __netif_tx_unlock(slave_txq); @@ -329,14 +364,21 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) busy = 1; break; case 1: - master->slaves = NEXT_SLAVE(q); + spin_lock_bh(&master->slaves_lock); + if (rcu_dereference_protected(master->slaves, + lockdep_is_held(&master->slaves_lock)) == q) + rcu_assign_pointer(master->slaves, + rcu_dereference_protected(NEXT_SLAVE(q), + lockdep_is_held(&master->slaves_lock))); + spin_unlock_bh(&master->slaves_lock); + rcu_read_unlock_bh(); return NETDEV_TX_OK; default: nores = 1; break; } __skb_pull(skb, skb_network_offset(skb)); - } while ((q = NEXT_SLAVE(q)) != start); + } while ((q = rcu_dereference_bh(NEXT_SLAVE(q))) != start); if (nores && skb_res == NULL) { skb_res = skb; @@ -345,29 +387,32 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) if (busy) { netif_stop_queue(dev); + rcu_read_unlock_bh(); return NETDEV_TX_BUSY; } master->tx_errors++; drop: master->tx_dropped++; + rcu_read_unlock_bh(); dev_kfree_skb(skb); return NETDEV_TX_OK; } static int teql_master_open(struct net_device *dev) { - struct Qdisc *q; + struct Qdisc *q, *first; struct teql_master *m = netdev_priv(dev); int mtu = 0xFFFE; unsigned int flags = IFF_NOARP | IFF_MULTICAST; - if (m->slaves == NULL) + first = rtnl_dereference(m->slaves); + if (!first) return -EUNATCH; flags = FMASK; - q = m->slaves; + q = first; do { struct net_device *slave = qdisc_dev(q); @@ -389,7 +434,7 @@ static int teql_master_open(struct net_device *dev) flags &= ~IFF_BROADCAST; if (!(slave->flags&IFF_MULTICAST)) flags &= ~IFF_MULTICAST; - } while ((q = NEXT_SLAVE(q)) != m->slaves); + } while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first); m->dev->mtu = mtu; m->dev->flags = (m->dev->flags&~FMASK) | flags; @@ -417,14 +462,15 @@ static void teql_master_stats64(struct net_device *dev, static int teql_master_mtu(struct net_device *dev, int new_mtu) { struct teql_master *m = netdev_priv(dev); - struct Qdisc *q; + struct Qdisc *q, *first; - q = m->slaves; + first = rtnl_dereference(m->slaves); + q = first; if (q) { do { if (new_mtu > qdisc_dev(q)->mtu) return -EINVAL; - } while ((q = NEXT_SLAVE(q)) != m->slaves); + } while ((q = rtnl_dereference(NEXT_SLAVE(q))) != first); } WRITE_ONCE(dev->mtu, new_mtu); @@ -444,6 +490,7 @@ static __init void teql_master_setup(struct net_device *dev) struct teql_master *master = netdev_priv(dev); struct Qdisc_ops *ops = &master->qops; + spin_lock_init(&master->slaves_lock); master->dev = dev; ops->priv_size = sizeof(struct teql_sched_data); diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 587b0017a67d..cf335494bffe 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -663,8 +663,9 @@ static void sctp_free_addr_wq(struct net *net) struct sctp_sockaddr_entry *addrw; struct sctp_sockaddr_entry *temp; + timer_shutdown_sync(&net->sctp.addr_wq_timer); + spin_lock_bh(&net->sctp.addr_wq_lock); - timer_delete(&net->sctp.addr_wq_timer); list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) { list_del(&addrw->list); kfree(addrw); diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 41958b8e59fd..8adac9e0cd66 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1761,6 +1761,8 @@ struct sctp_association *sctp_unpack_cookie( bear_cookie = &cookie->c; ch = (struct sctp_chunkhdr *)(bear_cookie + 1); + if (ch->type != SCTP_CID_INIT) + goto malformed; chlen = ntohs(ch->length); if (chlen < sizeof(struct sctp_init_chunk)) goto malformed; @@ -2298,7 +2300,8 @@ int sctp_verify_init(struct net *net, const struct sctp_endpoint *ep, * VIOLATION error. We build the ERROR chunk here and let the normal * error handling code build and send the packet. */ - if (param.v != (void *)chunk->chunk_end) + if (param.v != (void *)peer_init + + SCTP_PAD4(ntohs(peer_init->chunk_hdr.length))) return sctp_process_inv_paramlength(asoc, param.p, chunk, errp); /* The only missing mandatory param possible today is diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 8e920cef0858..d23d935e128e 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -707,11 +707,12 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net, struct sctp_cmd_seq *commands) { struct sctp_ulpevent *ev, *ai_ev = NULL, *auth_ev = NULL; + struct sctp_chunk *err_chk_p = NULL; struct sctp_association *new_asoc; struct sctp_init_chunk *peer_init; struct sctp_chunk *chunk = arg; - struct sctp_chunk *err_chk_p; struct sctp_chunk *repl; + enum sctp_cid cid; struct sock *sk; int error = 0; @@ -785,6 +786,19 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net, } } + peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1); + cid = peer_init->chunk_hdr.type; + if (!sctp_sk(sk)->cookie_auth_enable && + !sctp_verify_init(net, ep, asoc, cid, peer_init, chunk, + &err_chk_p)) { + sctp_association_free(new_asoc); + if (err_chk_p) + sctp_chunk_free(err_chk_p); + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); + } + if (err_chk_p) + sctp_chunk_free(err_chk_p); + if (security_sctp_assoc_request(new_asoc, chunk->head_skb ?: chunk->skb)) { sctp_association_free(new_asoc); return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); @@ -798,7 +812,6 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net, /* This is a brand-new association, so these are not yet side * effects--it is safe to run them here. */ - peer_init = (struct sctp_init_chunk *)(chunk->subh.cookie_hdr + 1); if (!sctp_process_init(new_asoc, chunk, &chunk->subh.cookie_hdr->c.peer_addr, peer_init, GFP_ATOMIC)) @@ -2215,10 +2228,12 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook( void *arg, struct sctp_cmd_seq *commands) { + struct sctp_chunk *err_chk_p = NULL; struct sctp_association *new_asoc; + struct sctp_init_chunk *peer_init; struct sctp_chunk *chunk = arg; enum sctp_disposition retval; - struct sctp_chunk *err_chk_p; + enum sctp_cid cid; int error = 0; char action; @@ -2287,6 +2302,21 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook( switch (action) { case 'A': /* Association restart. */ case 'B': /* Collision case B. */ + peer_init = (struct sctp_init_chunk *) + (chunk->subh.cookie_hdr + 1); + cid = peer_init->chunk_hdr.type; + if (!sctp_sk(ep->base.sk)->cookie_auth_enable && + !sctp_verify_init(net, ep, asoc, cid, peer_init, chunk, + &err_chk_p)) { + sctp_association_free(new_asoc); + if (err_chk_p) + sctp_chunk_free(err_chk_p); + return sctp_sf_pdiscard(net, ep, asoc, type, arg, + commands); + } + if (err_chk_p) + sctp_chunk_free(err_chk_p); + fallthrough; case 'D': /* Collision case D. */ /* Update socket peer label if first association. */ if (security_sctp_assoc_request((struct sctp_association *)asoc, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index c8481461f7d8..c7b9e325ec1c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4111,8 +4111,9 @@ static int sctp_setsockopt_reset_streams(struct sock *sk, if (optlen < sizeof(*params)) return -EINVAL; /* srs_number_streams is u16, so optlen can't be bigger than this. */ - optlen = min_t(unsigned int, optlen, USHRT_MAX + - sizeof(__u16) * sizeof(*params)); + optlen = min_t(unsigned int, optlen, + struct_size_t(struct sctp_reset_streams, srs_stream_list, + USHRT_MAX)); if (params->srs_number_streams * sizeof(__u16) > optlen - sizeof(*params)) @@ -4598,8 +4599,8 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, if (optlen > 0) { /* Trim it to the biggest size sctp sockopt may need if necessary */ optlen = min_t(unsigned int, optlen, - PAGE_ALIGN(USHRT_MAX + - sizeof(__u16) * sizeof(struct sctp_reset_streams))); + PAGE_ALIGN(struct_size_t(struct sctp_reset_streams, + srs_stream_list, USHRT_MAX))); kopt = memdup_sockptr(optval, optlen); if (IS_ERR(kopt)) return PTR_ERR(kopt); diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 76a1585d3f6b..10d1ec593084 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -497,12 +497,13 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, */ int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, struct tipc_msg *hdr, - struct sk_buff_head *retrq) + struct sk_buff_head *retrq, bool *valid) { struct sk_buff_head *inputq = &tipc_bc_base(net)->inputq; struct tipc_gap_ack_blks *ga; struct sk_buff_head xmitq; int rc = 0; + u16 glen; __skb_queue_head_init(&xmitq); @@ -510,13 +511,18 @@ int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, if (msg_type(hdr) != STATE_MSG) { tipc_link_bc_init_rcv(l, hdr); } else if (!msg_bc_ack_invalid(hdr)) { - tipc_get_gap_ack_blks(&ga, l, hdr, false); - if (!sysctl_tipc_bc_retruni) - retrq = &xmitq; - rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), - msg_bc_gap(hdr), ga, &xmitq, - retrq); - rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq); + glen = tipc_get_gap_ack_blks(&ga, l, hdr, false); + if (glen > msg_data_sz(hdr)) { + /* Malformed Gap ACK blocks; caller drops the msg */ + *valid = false; + } else { + if (!sysctl_tipc_bc_retruni) + retrq = &xmitq; + rc = tipc_link_bc_ack_rcv(l, msg_bcast_ack(hdr), + msg_bc_gap(hdr), ga, &xmitq, + retrq); + rc |= tipc_link_bc_sync_rcv(l, hdr, &xmitq); + } } tipc_bcast_unlock(net); diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 2d9352dc7b0e..55d17b5413e1 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -97,7 +97,7 @@ void tipc_bcast_ack_rcv(struct net *net, struct tipc_link *l, struct tipc_msg *hdr); int tipc_bcast_sync_rcv(struct net *net, struct tipc_link *l, struct tipc_msg *hdr, - struct sk_buff_head *retrq); + struct sk_buff_head *retrq, bool *valid); int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg, struct tipc_link *bcl); int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]); diff --git a/net/tipc/node.c b/net/tipc/node.c index 97aa970a0d83..8e4ef2630ae4 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1831,12 +1831,15 @@ static void tipc_node_mcast_rcv(struct tipc_node *n) } static void tipc_node_bc_sync_rcv(struct tipc_node *n, struct tipc_msg *hdr, - int bearer_id, struct sk_buff_head *xmitq) + int bearer_id, struct sk_buff_head *xmitq, + bool *valid) { struct tipc_link *ucl; int rc; - rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr, xmitq); + rc = tipc_bcast_sync_rcv(n->net, n->bc_entry.link, hdr, xmitq, valid); + if (!*valid) + return; if (rc & TIPC_LINK_DOWN_EVT) { tipc_node_reset_links(n); @@ -2140,12 +2143,18 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) /* Ensure broadcast reception is in synch with peer's send state */ if (unlikely(usr == LINK_PROTOCOL)) { + bool valid = true; + if (unlikely(skb_linearize(skb))) { tipc_node_put(n); goto discard; } hdr = buf_msg(skb); - tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq); + tipc_node_bc_sync_rcv(n, hdr, bearer_id, &xmitq, &valid); + if (!valid) { + tipc_node_put(n); + goto discard; + } } else if (unlikely(tipc_link_acked(n->bc_entry.link) != bc_ack)) { tipc_bcast_ack_rcv(net, n->bc_entry.link, hdr); } diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_events/trace-events-sample.c index ecc7db237f2e..0b7a6efdb247 100644 --- a/samples/trace_events/trace-events-sample.c +++ b/samples/trace_events/trace-events-sample.c @@ -107,6 +107,10 @@ int foo_bar_reg(void) * for consistency sake, we still take the thread_mutex. */ simple_tsk_fn = kthread_run(simple_thread_fn, NULL, "event-sample-fn"); + if (IS_ERR_OR_NULL(simple_tsk_fn)) { + pr_err("Failed to create simple_thread_fn\n"); + simple_tsk_fn = NULL; + } out: mutex_unlock(&thread_mutex); return 0; diff --git a/scripts/sorttable.c b/scripts/sorttable.c index e8ed11c680c6..d8dc2a1b7c31 100644 --- a/scripts/sorttable.c +++ b/scripts/sorttable.c @@ -891,17 +891,22 @@ static int do_file(char const *const fname, void *addr) table_sort_t custom_sort = NULL; switch (elf_map_machine(ehdr)) { - case EM_AARCH64: #ifdef MCOUNT_SORT_ENABLED + case EM_AARCH64: + /* arm64 also needs RELA-based weak-function fixups. */ sort_reloc = true; rela_type = 0x403; - /* arm64 uses patchable function entry placing before function */ + /* fallthrough */ + case EM_RISCV: + /* arm64 and RISC-V place patchable entries before the function. */ before_func = 8; +#else + case EM_AARCH64: + case EM_RISCV: #endif /* fallthrough */ case EM_386: case EM_LOONGARCH: - case EM_RISCV: case EM_S390: case EM_X86_64: custom_sort = sort_relative_table_with_data; diff --git a/security/bpf/hooks.c b/security/bpf/hooks.c index 40efde233f3a..7b98f5d1e2be 100644 --- a/security/bpf/hooks.c +++ b/security/bpf/hooks.c @@ -7,6 +7,8 @@ #include #include +bool bpf_lsm_initialized __ro_after_init; + static struct security_hook_list bpf_lsm_hooks[] __ro_after_init = { #define LSM_HOOK(RET, DEFAULT, NAME, ...) \ LSM_HOOK_INIT(NAME, bpf_lsm_##NAME), @@ -24,6 +26,7 @@ static int __init bpf_lsm_init(void) { security_add_hooks(bpf_lsm_hooks, ARRAY_SIZE(bpf_lsm_hooks), &bpf_lsmid); + bpf_lsm_initialized = true; pr_info("LSM support for eBPF active\n"); return 0; } diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index df0a049192de..e394205f469b 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 33c9dd48b3b0..f16e2e223494 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c index d9e2384fc0ba..f7700713dc62 100644 --- a/sound/hda/codecs/realtek/alc269.c +++ b/sound/hda/codecs/realtek/alc269.c @@ -7068,6 +7068,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x88d1, "HP Pavilion 15-eh1xxx (mainboard 88D1)", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT), SND_PCI_QUIRK(0x103c, 0x88dd, "HP Pavilion 15z-ec200", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x88eb, "HP Victus 16-e0xxx", ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT), + SND_PCI_QUIRK(0x103c, 0x88ee, "HP Victus 16-e0xxx (MB 88EE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT), SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x890e, "HP 255 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8919, "HP Pavilion Aero Laptop 13-be0xxx", ALC287_FIXUP_HP_GPIO_LED), diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c index 96d8cc6c2324..fdf406e92fca 100644 --- a/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c @@ -6,7 +6,6 @@ // // Author: Lucas Tanure -#include #include #include diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c index 2acbaf8467a0..aab2066a20eb 100644 --- a/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c +++ b/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c @@ -6,7 +6,6 @@ // // Author: Lucas Tanure -#include #include #include diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c index 93bf12116626..69a22fdfeedb 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c index 3978d58ad020..4899ea372798 100644 --- a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c +++ b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/hda/core/hda_bus_type.c b/sound/hda/core/hda_bus_type.c index eb72a7af2e56..a4afd41b6f84 100644 --- a/sound/hda/core/hda_bus_type.c +++ b/sound/hda/core/hda_bus_type.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index a405cc2c11a3..d6df7de70b27 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -528,6 +528,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Raider A18 HX A9WJG"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m15 R7 AMD"), + } + }, { .driver_data = &acp6x_card, .matches = { diff --git a/sound/soc/atmel/sam9x5_wm8731.c b/sound/soc/atmel/sam9x5_wm8731.c index 1b5ef4e9d2b8..a603e4a57d50 100644 --- a/sound/soc/atmel/sam9x5_wm8731.c +++ b/sound/soc/atmel/sam9x5_wm8731.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/adau1372-i2c.c b/sound/soc/codecs/adau1372-i2c.c index 4217b7fc349c..bdb3e3a8509d 100644 --- a/sound/soc/codecs/adau1372-i2c.c +++ b/sound/soc/codecs/adau1372-i2c.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/codecs/adau1372-spi.c b/sound/soc/codecs/adau1372-spi.c index 656bd1fabeb3..a12961e2fb1e 100644 --- a/sound/soc/codecs/adau1372-spi.c +++ b/sound/soc/codecs/adau1372-spi.c @@ -6,7 +6,6 @@ * Author: Lars-Peter Clausen */ -#include #include #include #include diff --git a/sound/soc/codecs/adau1372.c b/sound/soc/codecs/adau1372.c index 879afeb81c42..cc174ec3a1f8 100644 --- a/sound/soc/codecs/adau1372.c +++ b/sound/soc/codecs/adau1372.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index a329e5bddb99..ae73136d0a6e 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c index 7c9242c2ff94..eb6f63d63783 100644 --- a/sound/soc/codecs/adau1761-spi.c +++ b/sound/soc/codecs/adau1761-spi.c @@ -6,7 +6,6 @@ * Author: Lars-Peter Clausen */ -#include #include #include #include diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 0e7954148af7..3ab624417f12 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c index 1a09633d5a88..0e6d42b10077 100644 --- a/sound/soc/codecs/adau1781-spi.c +++ b/sound/soc/codecs/adau1781-spi.c @@ -6,7 +6,6 @@ * Author: Lars-Peter Clausen */ -#include #include #include #include diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c index fc7ed5c1dd74..d1c6c4ddf506 100644 --- a/sound/soc/codecs/adau1977-i2c.c +++ b/sound/soc/codecs/adau1977-i2c.c @@ -7,7 +7,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c index e7e95e5d1911..878cde9d1014 100644 --- a/sound/soc/codecs/adau1977-spi.c +++ b/sound/soc/codecs/adau1977-spi.c @@ -6,7 +6,6 @@ * Author: Lars-Peter Clausen */ -#include #include #include #include diff --git a/sound/soc/codecs/adau7118-hw.c b/sound/soc/codecs/adau7118-hw.c index 45a5d2dcc0f2..92b226b8b4bb 100644 --- a/sound/soc/codecs/adau7118-hw.c +++ b/sound/soc/codecs/adau7118-hw.c @@ -6,7 +6,6 @@ // Copyright 2019 Analog Devices Inc. #include -#include #include #include "adau7118.h" diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index a33cb329865c..6ea7cb78cd44 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -5,7 +5,6 @@ * Copyright (c) 2009 Daniel Mack */ -#include #include #include #include diff --git a/sound/soc/codecs/audio-iio-aux.c b/sound/soc/codecs/audio-iio-aux.c index 066e401912b0..964b9a5b2990 100644 --- a/sound/soc/codecs/audio-iio-aux.c +++ b/sound/soc/codecs/audio-iio-aux.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c index 89c424dd838b..a889fbd519a8 100644 --- a/sound/soc/codecs/cs4234.c +++ b/sound/soc/codecs/cs4234.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 47cb10eb21bb..47b2f903a32c 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -19,7 +19,6 @@ * - Power management is supported */ -#include #include #include #include diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c index b8256ce0b8fb..ad1256910a18 100644 --- a/sound/soc/codecs/cs42l42-sdw.c +++ b/sound/soc/codecs/cs42l42-sdw.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/cs42l43.c b/sound/soc/codecs/cs42l43.c index f0d6ff0b2976..1d133577702e 100644 --- a/sound/soc/codecs/cs42l43.c +++ b/sound/soc/codecs/cs42l43.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index 31debe2d8231..4427d3214dee 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/sound/soc/codecs/cs42xx8-spi.c b/sound/soc/codecs/cs42xx8-spi.c index b86fe2fe771e..2e4b8e6c4081 100644 --- a/sound/soc/codecs/cs42xx8-spi.c +++ b/sound/soc/codecs/cs42xx8-spi.c @@ -6,7 +6,6 @@ * */ -#include #include #include #include diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index ced1270c4d68..6ac6d306b054 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -7,7 +7,6 @@ * Authors: Tim Howe */ -#include #include #include #include diff --git a/sound/soc/codecs/es8316.c b/sound/soc/codecs/es8316.c index 6a428387e496..3abe77423f29 100644 --- a/sound/soc/codecs/es8316.c +++ b/sound/soc/codecs/es8316.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/es8323.c b/sound/soc/codecs/es8323.c index d067f7bda03a..b926340256be 100644 --- a/sound/soc/codecs/es8323.c +++ b/sound/soc/codecs/es8323.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/es9356.c b/sound/soc/codecs/es9356.c index 8db81d574624..1122455aab77 100644 --- a/sound/soc/codecs/es9356.c +++ b/sound/soc/codecs/es9356.c @@ -7,7 +7,6 @@ // #include -#include #include #include #include diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index 528d5b167ecf..58a5798823d7 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -244,6 +244,11 @@ static const struct va_macro_data sm8250_va_data = { .version = LPASS_CODEC_VERSION_1_0, }; +static const struct va_macro_data sc7280_va_data = { + .has_swr_master = false, + .has_npl_clk = false, +}; + static const struct va_macro_data sm8450_va_data = { .has_swr_master = true, .has_npl_clk = true, @@ -1755,7 +1760,7 @@ static const struct dev_pm_ops va_macro_pm_ops = { }; static const struct of_device_id va_macro_dt_match[] = { - { .compatible = "qcom,sc7280-lpass-va-macro", .data = &sm8250_va_data }, + { .compatible = "qcom,sc7280-lpass-va-macro", .data = &sc7280_va_data }, { .compatible = "qcom,sm6115-lpass-va-macro", .data = &sm8450_va_data }, { .compatible = "qcom,sm8250-lpass-va-macro", .data = &sm8250_va_data }, { .compatible = "qcom,sm8450-lpass-va-macro", .data = &sm8450_va_data }, diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index cc811f58c9d2..b0f8043fb9e2 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index 20de379d08de..8805bd01153c 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 7a42052dc051..8fe9c58e1a62 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/max98388.c b/sound/soc/codecs/max98388.c index 2576841b7de2..a4c57152d25f 100644 --- a/sound/soc/codecs/max98388.c +++ b/sound/soc/codecs/max98388.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/mt6351.c b/sound/soc/codecs/mt6351.c index 2a5e963fb2b5..1768c249650d 100644 --- a/sound/soc/codecs/mt6351.c +++ b/sound/soc/codecs/mt6351.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index a787accb88e8..ed8cbc63fa77 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -6,7 +6,6 @@ // Author: KaiChieh Chuang #include -#include #include #include #include diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c index 334f344761aa..dd24027836b2 100644 --- a/sound/soc/codecs/pcm3168a-i2c.c +++ b/sound/soc/codecs/pcm3168a-i2c.c @@ -10,7 +10,6 @@ #include #include #include -#include #include diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c index 91d3d43cd998..95405cea8143 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.c +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 60e5040b6dd9..2f30497498c7 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 5e8eda6a5f7f..ca318dbd946e 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index 51bd11b92a55..c038ac0e3b76 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index 13493b85f3c9..1e930b27c67a 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 6bc636c86f42..a451d5d1f8ab 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index 461315844ba9..e028a1c3a9ac 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index df3c43f2ab6b..a0c6a9efa840 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index 8b7d50a80ff9..85779547653e 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -7,7 +7,6 @@ // #include -#include #include #include #include diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index 2787524c796e..70d661ce2ef2 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index fabd21bbbe5b..1b183b21a4b8 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index a4a3945522e8..f5ec348a9628 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -9,7 +9,6 @@ */ #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c index 02df04a0ddad..041b381e582b 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.c +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index 284900933ebf..e68aa0350a5b 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/sound/soc/codecs/rt9123.c b/sound/soc/codecs/rt9123.c index 84fd3d6861de..07eaf275c9e9 100644 --- a/sound/soc/codecs/rt9123.c +++ b/sound/soc/codecs/rt9123.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rt9123p.c b/sound/soc/codecs/rt9123p.c index d509659e735b..584fcb78cd3f 100644 --- a/sound/soc/codecs/rt9123p.c +++ b/sound/soc/codecs/rt9123p.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rtq9124.c b/sound/soc/codecs/rtq9124.c index 186904b31434..2a041894bc0c 100644 --- a/sound/soc/codecs/rtq9124.c +++ b/sound/soc/codecs/rtq9124.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c index 14a2c0723d33..573200e5062f 100644 --- a/sound/soc/codecs/rtq9128.c +++ b/sound/soc/codecs/rtq9128.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c index b7e6546f1b5a..93f3fd1882a5 100644 --- a/sound/soc/codecs/sdw-mockup.c +++ b/sound/soc/codecs/sdw-mockup.c @@ -8,7 +8,6 @@ // #include -#include #include #include #include diff --git a/sound/soc/codecs/simple-amplifier.c b/sound/soc/codecs/simple-amplifier.c index ca0e6ce8cc37..ca53b08c0b33 100644 --- a/sound/soc/codecs/simple-amplifier.c +++ b/sound/soc/codecs/simple-amplifier.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/codecs/sma1303.c b/sound/soc/codecs/sma1303.c index c7aaf98ef71e..7fce60de5e5f 100644 --- a/sound/soc/codecs/sma1303.c +++ b/sound/soc/codecs/sma1303.c @@ -7,7 +7,6 @@ // Auther: Gyuhwa Park // Kiseok Jo -#include #include #include #include diff --git a/sound/soc/codecs/src4xxx-i2c.c b/sound/soc/codecs/src4xxx-i2c.c index 34b3abdb9a70..4157f7787801 100644 --- a/sound/soc/codecs/src4xxx-i2c.c +++ b/sound/soc/codecs/src4xxx-i2c.c @@ -6,7 +6,6 @@ // Author: Matt Flax #include -#include #include #include diff --git a/sound/soc/codecs/tas675x.c b/sound/soc/codecs/tas675x.c index 6f89a422f3c6..82526362de7b 100644 --- a/sound/soc/codecs/tas675x.c +++ b/sound/soc/codecs/tas675x.c @@ -954,10 +954,10 @@ static const struct snd_kcontrol_new tas675x_snd_controls[] = { /* Temperature and Voltage Monitoring */ SOC_SINGLE_RO("PVDD Sense", TAS675X_PVDD_SENSE_REG, 0, 0xFF), SOC_SINGLE_RO("Global Temperature", TAS675X_TEMP_GLOBAL_REG, 0, 0xFF), - SOC_SINGLE_RO("CH1 Temperature Range", TAS675X_TEMP_CH1_CH2_REG, 6, 3), - SOC_SINGLE_RO("CH2 Temperature Range", TAS675X_TEMP_CH1_CH2_REG, 4, 3), - SOC_SINGLE_RO("CH3 Temperature Range", TAS675X_TEMP_CH3_CH4_REG, 2, 3), - SOC_SINGLE_RO("CH4 Temperature Range", TAS675X_TEMP_CH3_CH4_REG, 0, 3), + SOC_SINGLE_RO("CH1 Temperature Range", TAS675X_TEMP_CH1_CH2_REG, 0, 7), + SOC_SINGLE_RO("CH2 Temperature Range", TAS675X_TEMP_CH1_CH2_REG, 3, 7), + SOC_SINGLE_RO("CH3 Temperature Range", TAS675X_TEMP_CH3_CH4_REG, 0, 7), + SOC_SINGLE_RO("CH4 Temperature Range", TAS675X_TEMP_CH3_CH4_REG, 3, 7), /* Speaker Protection & Detection */ SOC_SINGLE("Tweeter Detection Switch", TAS675X_TWEETER_DETECT_CTRL_REG, 0, 1, 1), @@ -1133,7 +1133,7 @@ static int tas675x_hw_params(struct snd_pcm_substream *substream, * Single clock domain: SDIN and SDOUT share one SCLK/FSYNC pair, * so all active DAIs must use the same sample rate. */ - if ((tas->active_playback_dais || tas->active_capture_dais) && + if ((READ_ONCE(tas->active_playback_dais) || READ_ONCE(tas->active_capture_dais)) && tas->rate && tas->rate != rate) { dev_err(component->dev, "Rate %u conflicts with active rate %u\n", @@ -1397,14 +1397,14 @@ static int tas675x_mute_stream(struct snd_soc_dai *dai, int mute, int direction) set_bit(dai->id, &tas->active_playback_dais); /* Last playback stream */ - if (mute && !tas->active_playback_dais) { + if (mute && !READ_ONCE(tas->active_playback_dais)) { ret = tas675x_set_state_all(tas, TAS675X_STATE_SLEEP_BOTH); regmap_read(tas->regmap, TAS675X_CLK_FAULT_LATCHED_REG, &discard); return ret; } return tas675x_set_state_all(tas, - tas->active_playback_dais ? + READ_ONCE(tas->active_playback_dais) ? TAS675X_STATE_PLAY_BOTH : TAS675X_STATE_SLEEP_BOTH); } diff --git a/sound/soc/codecs/uda1334.c b/sound/soc/codecs/uda1334.c index f799772ff747..54c5cb5b3d4b 100644 --- a/sound/soc/codecs/uda1334.c +++ b/sound/soc/codecs/uda1334.c @@ -4,7 +4,6 @@ // // Based on WM8523 ALSA SoC Audio driver written by Mark Brown -#include #include #include #include diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 589a89564813..137dcd3d7487 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -7,7 +7,6 @@ * Author: Liam Girdwood */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 65108a041c92..b8832a1d61fe 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -7,7 +7,6 @@ * Author: Mark Brown */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index 6b1a7450b0ac..23daf158f35f 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -8,7 +8,6 @@ * Based on WM8523 ALSA SoC Audio driver written by Mark Brown */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index ca7bbe5d4fc3..eb374ba6e5b5 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -15,7 +15,6 @@ * the secondary audio interfaces are not. */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 5271966b1615..2db8829661c3 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -9,7 +9,6 @@ * Based on wm8731.c by Richard Purdie */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 6e6fd77c3020..3109a6a0df74 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -7,7 +7,6 @@ * Author: Mark Brown */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8731-i2c.c b/sound/soc/codecs/wm8731-i2c.c index 5d19fcc46606..f44f4d3d9394 100644 --- a/sound/soc/codecs/wm8731-i2c.c +++ b/sound/soc/codecs/wm8731-i2c.c @@ -11,7 +11,6 @@ */ #include -#include #include #include "wm8731.h" diff --git a/sound/soc/codecs/wm8731-spi.c b/sound/soc/codecs/wm8731-spi.c index c02086afa7fb..29e58e1e6b79 100644 --- a/sound/soc/codecs/wm8731-spi.c +++ b/sound/soc/codecs/wm8731-spi.c @@ -11,7 +11,6 @@ */ #include -#include #include #include "wm8731.h" diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 4eb42d19bc7e..33a3f88fffb3 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -7,7 +7,6 @@ * Author: Mark Brown */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 95b23504f68d..ac4008b4832d 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -26,7 +26,6 @@ * an alsa kcontrol. This allows the PCM to remain open. */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index d382b476c89c..b8b4d1e823e6 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -7,7 +7,6 @@ * Author: Dimitris Papastamos */ -#include #include #include #include diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index f3b02c77314f..a8e4f71c77d1 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -9,7 +9,6 @@ * TODO: Input ALC/limiter support */ -#include #include #include #include diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index da401561e2de..8f2aa8f7d4e8 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 8554fb690772..c21104355aa0 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c @@ -5,7 +5,6 @@ // Copyright (C) 2009 Jon Smirl, Digispeaker // Author: Jon Smirl -#include #include #include #include diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c index 7151d426bee9..14b212675240 100644 --- a/sound/soc/generic/audio-graph-card2-custom-sample.c +++ b/sound/soc/generic/audio-graph-card2-custom-sample.c @@ -6,7 +6,6 @@ // Copyright (C) 2020 Kuninori Morimoto // #include -#include #include #include #include diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c index 517619531615..d36bbc820618 100644 --- a/sound/soc/jz4740/jz4740-i2s.c +++ b/sound/soc/jz4740/jz4740-i2s.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c index 10f9ef73c130..90448df6c0b2 100644 --- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index 4f6594cc723c..cfd6438dbcb3 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2018, Linaro Limited -#include #include #include #include diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index abdd58c1d0a4..d3d8a6e83268 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index c8d5ac43a176..1e0eda8c24c4 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/renesas/rcar/adg.c b/sound/soc/renesas/rcar/adg.c index 5479cefb6dbe..53efd1be5139 100644 --- a/sound/soc/renesas/rcar/adg.c +++ b/sound/soc/renesas/rcar/adg.c @@ -45,6 +45,7 @@ struct rsnd_adg { struct rsnd_mod mod; int clkin_rate[CLKINMAX]; bool ssi_clk_prepared; + bool clk_enabled; int clkin_size; int clkout_size; u32 ckr; @@ -463,6 +464,22 @@ int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) struct clk *clk; int ret = 0, i; + /* + * rsnd_adg_clk_enable() and rsnd_adg_clk_disable() can be called + * redundantly, for example when system suspend follows a resume + * whose enable failed. Make this function idempotent so that the + * "adg" clock, which has no clkin_rate[] style guard, is never + * disabled twice. + */ + if (enable) { + if (adg->clk_enabled) + return 0; + } else { + if (!adg->clk_enabled) + return 0; + adg->clk_enabled = false; + } + if (enable) { ret = clk_prepare_enable(adg->adg); if (ret < 0) @@ -520,12 +537,22 @@ int rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) * rsnd_adg_clk_enable() might return error (_disable() will not). * We need to rollback in such case */ - if (ret < 0) + if (ret < 0) { + /* + * Mark as enabled so that the rollback below is not + * short-circuited by the idempotency guard. It clears + * the flag again on its way through. + */ + adg->clk_enabled = true; rsnd_adg_clk_disable(priv); + return ret; + } /* disable adg */ if (!enable) clk_disable_unprepare(adg->adg); + else + adg->clk_enabled = true; return ret; } diff --git a/sound/soc/renesas/rcar/src.c b/sound/soc/renesas/rcar/src.c index ac806bdc96d9..2cdb39e898af 100644 --- a/sound/soc/renesas/rcar/src.c +++ b/sound/soc/renesas/rcar/src.c @@ -850,6 +850,7 @@ void rsnd_src_suspend(struct rsnd_priv *priv) clk_disable_unprepare(src_ctrl->scu_x2); clk_disable_unprepare(src_ctrl->scu); + clk_disable_unprepare(src_ctrl->scu_supply); } void rsnd_src_resume(struct rsnd_priv *priv) @@ -861,6 +862,7 @@ void rsnd_src_resume(struct rsnd_priv *priv) if (!src_ctrl) return; + clk_prepare_enable(src_ctrl->scu_supply); clk_prepare_enable(src_ctrl->scu); clk_prepare_enable(src_ctrl->scu_x2); diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c index 6937a91ddfb9..8d7b007a068f 100644 --- a/sound/soc/sdca/sdca_class.c +++ b/sound/soc/sdca/sdca_class.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/sof/sof-client-ipc-flood-test.c b/sound/soc/sof/sof-client-ipc-flood-test.c index 7b72d1c9c739..2396cc35489a 100644 --- a/sound/soc/sof/sof-client-ipc-flood-test.c +++ b/sound/soc/sof/sof-client-ipc-flood-test.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/sof/sof-client-ipc-kernel-injector.c b/sound/soc/sof/sof-client-ipc-kernel-injector.c index d5984990098a..02d0d97ad1a0 100644 --- a/sound/soc/sof/sof-client-ipc-kernel-injector.c +++ b/sound/soc/sof/sof-client-ipc-kernel-injector.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/sof/sof-client-ipc-msg-injector.c b/sound/soc/sof/sof-client-ipc-msg-injector.c index c28f106de6ba..932ab459c079 100644 --- a/sound/soc/sof/sof-client-ipc-msg-injector.c +++ b/sound/soc/sof/sof-client-ipc-msg-injector.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/sof/sof-client-probes-ipc3.c b/sound/soc/sof/sof-client-probes-ipc3.c index a78ec0954a61..a3e382d6161f 100644 --- a/sound/soc/sof/sof-client-probes-ipc3.c +++ b/sound/soc/sof/sof-client-probes-ipc3.c @@ -107,7 +107,7 @@ static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd, struct device *dev = &cdev->auxdev.dev; struct sof_ipc_probe_info_params msg = {{{0}}}; struct sof_ipc_probe_info_params *reply; - size_t bytes; + size_t bytes, elem_size, payload_size; int ret; *params = NULL; @@ -128,14 +128,29 @@ static int ipc3_probes_info(struct sof_client_dev *cdev, unsigned int cmd, if (ret < 0 || reply->rhdr.error < 0) goto exit; + payload_size = reply->rhdr.hdr.size; + if (payload_size < offsetof(struct sof_ipc_probe_info_params, dma)) { + ret = -EINVAL; + goto exit; + } + if (!reply->num_elems) goto exit; if (cmd == SOF_IPC_PROBE_DMA_INFO) - bytes = sizeof(reply->dma[0]); + elem_size = sizeof(reply->dma[0]); else - bytes = sizeof(reply->desc[0]); - bytes *= reply->num_elems; + elem_size = sizeof(reply->desc[0]); + + payload_size -= offsetof(struct sof_ipc_probe_info_params, dma); + if (reply->num_elems > payload_size / elem_size) { + dev_err(dev, "%s: invalid probe info element count %u\n", + __func__, reply->num_elems); + ret = -EINVAL; + goto exit; + } + + bytes = reply->num_elems * elem_size; *params = kmemdup(&reply->dma[0], bytes, GFP_KERNEL); if (!*params) { ret = -ENOMEM; diff --git a/sound/soc/sof/sof-client-probes-ipc4.c b/sound/soc/sof/sof-client-probes-ipc4.c index 88397c7dc4c3..2eef32b55395 100644 --- a/sound/soc/sof/sof-client-probes-ipc4.c +++ b/sound/soc/sof/sof-client-probes-ipc4.c @@ -248,10 +248,19 @@ static int ipc4_probes_points_info(struct sof_client_dev *cdev, return ret; } info = msg.data_ptr; + if (msg.data_size < sizeof(*info) || + info->num_elems > (msg.data_size - sizeof(*info)) / + sizeof(info->points[0])) { + dev_err(dev, "%s: invalid probe info element count %u\n", + __func__, info->num_elems); + kfree(msg.data_ptr); + return -EINVAL; + } + *num_desc = info->num_elems; dev_dbg(dev, "%s: got %zu probe points", __func__, *num_desc); - *desc = kzalloc(*num_desc * sizeof(**desc), GFP_KERNEL); + *desc = kcalloc(*num_desc, sizeof(**desc), GFP_KERNEL); if (!*desc) { kfree(msg.data_ptr); return -ENOMEM; diff --git a/sound/soc/sunxi/sun50i-codec-analog.c b/sound/soc/sunxi/sun50i-codec-analog.c index a19f8aaaf1c4..9f5b067a8ccc 100644 --- a/sound/soc/sunxi/sun50i-codec-analog.c +++ b/sound/soc/sunxi/sun50i-codec-analog.c @@ -13,7 +13,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index eddfebe16616..5c784b1f6846 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c index 7135aa23a7fc..7f360dfaf8b1 100644 --- a/sound/soc/tegra/tegra186_asrc.c +++ b/sound/soc/tegra/tegra186_asrc.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 7cf7d6dbfc35..0d3807b231f3 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 38661d9b4a7c..5eefcf149ae3 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 9b662fcee66f..15a94196ee1a 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index 930b080aec0a..cc1f9c158191 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index 3e42e2c75eb9..6098ad056ba9 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index 0259b137547c..ff8c72fc38c5 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c index c237ba7531de..a69774578d69 100644 --- a/sound/soc/tegra/tegra210_mixer.c +++ b/sound/soc/tegra/tegra210_mixer.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index b55f8142c4a4..ac04350107c4 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c index ad4c400281e8..30a54b1222d9 100644 --- a/sound/soc/tegra/tegra210_ope.c +++ b/sound/soc/tegra/tegra210_ope.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include diff --git a/sound/soc/ti/omap-dmic.c b/sound/soc/ti/omap-dmic.c index 7ca46c57566d..b795b9f66b0e 100644 --- a/sound/soc/ti/omap-dmic.c +++ b/sound/soc/ti/omap-dmic.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/sound/soc/ti/omap-mcpdm.c b/sound/soc/ti/omap-mcpdm.c index c7d7b502f120..5698d2f26973 100644 --- a/sound/soc/ti/omap-mcpdm.c +++ b/sound/soc/ti/omap-mcpdm.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include diff --git a/sound/usb/usx2y/us144mkii.c b/sound/usb/usx2y/us144mkii.c index 94553b61013c..58ef23146f20 100644 --- a/sound/usb/usx2y/us144mkii.c +++ b/sound/usb/usx2y/us144mkii.c @@ -585,19 +585,24 @@ static void tascam_disconnect(struct usb_interface *intf) return; if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { - /* Ensure all deferred work is complete before freeing resources */ snd_card_disconnect(tascam->card); - cancel_work_sync(&tascam->stop_work); - cancel_work_sync(&tascam->capture_work); - cancel_work_sync(&tascam->midi_in_work); - cancel_work_sync(&tascam->midi_out_work); - cancel_work_sync(&tascam->stop_pcm_work); + /* + * Kill the URBs before cancelling the work, so a late URB + * completion cannot re-arm a work that then runs after + * snd_card_free(). + */ usb_kill_anchored_urbs(&tascam->playback_anchor); usb_kill_anchored_urbs(&tascam->capture_anchor); usb_kill_anchored_urbs(&tascam->feedback_anchor); usb_kill_anchored_urbs(&tascam->midi_in_anchor); usb_kill_anchored_urbs(&tascam->midi_out_anchor); + + cancel_work_sync(&tascam->stop_work); + cancel_work_sync(&tascam->capture_work); + cancel_work_sync(&tascam->midi_in_work); + cancel_work_sync(&tascam->midi_out_work); + cancel_work_sync(&tascam->stop_pcm_work); timer_delete_sync(&tascam->error_timer); tascam_free_urbs(tascam); snd_card_free(tascam->card); diff --git a/sound/usb/usx2y/us144mkii_capture.c b/sound/usb/usx2y/us144mkii_capture.c index af120bf62173..fa01da98151a 100644 --- a/sound/usb/usx2y/us144mkii_capture.c +++ b/sound/usb/usx2y/us144mkii_capture.c @@ -302,7 +302,6 @@ void capture_urb_complete(struct urb *urb) } usb_get_urb(urb); - usb_anchor_urb(urb, &tascam->capture_anchor); ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { dev_err_ratelimited(tascam->card->dev, @@ -312,6 +311,7 @@ void capture_urb_complete(struct urb *urb) usb_put_urb(urb); atomic_dec( &tascam->active_urbs); /* Decrement on failed resubmission */ + return; } out: usb_put_urb(urb); diff --git a/tools/testing/cxl/test/mem.c b/tools/testing/cxl/test/mem.c index a1d170f88fee..a7da279aa3ef 100644 --- a/tools/testing/cxl/test/mem.c +++ b/tools/testing/cxl/test/mem.c @@ -2,7 +2,6 @@ // Copyright(c) 2021 Intel Corporation. All rights reserved. #include -#include #include #include #include diff --git a/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c b/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c index 621b3b71888e..1d7231728eaf 100644 --- a/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c +++ b/tools/testing/selftests/bpf/prog_tests/sockmap_strp.c @@ -431,6 +431,35 @@ static void test_sockmap_strp_verdict(int family, int sotype) test_sockmap_strp__destroy(strp); } +static void test_sockmap_strp_parser_reject(void) +{ + struct test_sockmap_strp *strp = NULL; + int parser_mod, parser_ro, link; + int err, map; + + strp = test_sockmap_strp__open_and_load(); + if (!ASSERT_OK_PTR(strp, "test_sockmap_strp__open_and_load")) + return; + + map = bpf_map__fd(strp->maps.sock_map); + parser_mod = bpf_program__fd(strp->progs.prog_skb_parser_resize); + parser_ro = bpf_program__fd(strp->progs.prog_skb_parser); + + err = bpf_prog_attach(parser_mod, map, BPF_SK_SKB_STREAM_PARSER, 0); + ASSERT_ERR(err, "bpf_prog_attach parser_mod"); + + link = bpf_link_create(parser_ro, map, BPF_SK_SKB_STREAM_PARSER, NULL); + if (!ASSERT_GE(link, 0, "bpf_link_create parser_ro")) + goto out; + + err = bpf_link_update(link, parser_mod, NULL); + ASSERT_ERR(err, "bpf_link_update parser_mod"); +out: + if (link >= 0) + close(link); + test_sockmap_strp__destroy(strp); +} + void test_sockmap_strp(void) { if (test__start_subtest("sockmap strp tcp pass")) @@ -451,4 +480,6 @@ void test_sockmap_strp(void) test_sockmap_strp_multiple_pkt(AF_INET, SOCK_STREAM); if (test__start_subtest("sockmap strp tcp dispatch")) test_sockmap_strp_dispatch_pkt(AF_INET, SOCK_STREAM); + if (test__start_subtest("sockmap strp parser reject pkt mod")) + test_sockmap_strp_parser_reject(); } diff --git a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c index 7247a20c0a3b..024ef2aae200 100644 --- a/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/refcounted_kptr_fail.c @@ -13,12 +13,20 @@ struct node_acquire { struct bpf_refcount refcount; }; +struct node_refcounted { + long key; + struct bpf_list_node list; + struct bpf_refcount refcount; +}; + extern void bpf_rcu_read_lock(void) __ksym; extern void bpf_rcu_read_unlock(void) __ksym; #define private(name) SEC(".data." #name) __hidden __attribute__((aligned(8))) private(A) struct bpf_spin_lock glock; private(A) struct bpf_rb_root groot __contains(node_acquire, node); +private(B) struct bpf_spin_lock lock; +private(B) struct bpf_list_head head __contains(node_refcounted, list); static bool less(struct bpf_rb_node *a, const struct bpf_rb_node *b) { @@ -93,6 +101,32 @@ long rbtree_refcounted_node_ref_escapes_owning_input(void *ctx) return 0; } +SEC("?tc") +__failure __msg("dereference of modified ptr_ ptr R1") +long refcount_acquire_list_node_offset(void *ctx) +{ + struct node_refcounted *node, *base, *ref; + struct bpf_list_node *list_node; + + node = bpf_obj_new(typeof(*node)); + if (!node) + return 1; + + bpf_spin_lock(&lock); + bpf_list_push_front(&head, &node->list); + list_node = bpf_list_pop_front(&head); + bpf_spin_unlock(&lock); + if (!list_node) + return 2; + + base = container_of(list_node, struct node_refcounted, list); + ref = bpf_refcount_acquire(list_node); + if (ref) + bpf_obj_drop(ref); + bpf_obj_drop(base); + return 0; +} + SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") __failure __msg("function calls are not allowed while holding a lock") int BPF_PROG(rbtree_fail_sleepable_lock_across_rcu, diff --git a/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c index c9abfe3a11af..56e9aebf05f2 100644 --- a/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c +++ b/tools/testing/selftests/bpf/progs/sockmap_parse_prog.c @@ -5,28 +5,6 @@ SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { - void *data_end = (void *)(long) skb->data_end; - void *data = (void *)(long) skb->data; - __u8 *d = data; - int err; - - if (data + 10 > data_end) { - err = bpf_skb_pull_data(skb, 10); - if (err) - return SK_DROP; - - data_end = (void *)(long)skb->data_end; - data = (void *)(long)skb->data; - if (data + 10 > data_end) - return SK_DROP; - } - - /* This write/read is a bit pointless but tests the verifier and - * strparser handler for read/write pkt data and access into sk - * fields. - */ - d = data; - d[7] = 1; return skb->len; } diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_strp.c b/tools/testing/selftests/bpf/progs/test_sockmap_strp.c index dde3d5bec515..fe88fa6d40bc 100644 --- a/tools/testing/selftests/bpf/progs/test_sockmap_strp.c +++ b/tools/testing/selftests/bpf/progs/test_sockmap_strp.c @@ -50,4 +50,11 @@ int prog_skb_parser_partial(struct __sk_buff *skb) return 10; } +SEC("sk_skb/stream_parser") +int prog_skb_parser_resize(struct __sk_buff *skb) +{ + bpf_skb_change_tail(skb, skb->len, 0); + return skb->len; +} + char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/verifier_unpriv.c b/tools/testing/selftests/bpf/progs/verifier_unpriv.c index 49f7bd05edad..42de5cff7e52 100644 --- a/tools/testing/selftests/bpf/progs/verifier_unpriv.c +++ b/tools/testing/selftests/bpf/progs/verifier_unpriv.c @@ -6,6 +6,8 @@ #include "../../../include/linux/filter.h" #include "bpf_misc.h" +extern const int bpf_prog_active __ksym; + #define BPF_SK_LOOKUP(func) \ /* struct bpf_sock_tuple tuple = {} */ \ "r2 = 0;" \ @@ -77,6 +79,23 @@ __naked void dummy_prog_loop1_socket(void) : __clobber_all); } +SEC("socket") +__description("unpriv: pseudo btf id log masks address") +__success_unpriv +__msg_unpriv("0: (18) r1 = 0x0") +__not_msg_unpriv("0: (18) r1 = 0x{{[1-9a-f][0-9a-f]*}}") +__retval_unpriv(0) +__log_level(2) +__naked void pseudo_btf_id_log_masks_address(void) +{ + asm volatile ("r1 = %[bpf_prog_active] ll;" + "r0 = 0;" + "exit;" + : + : __imm_addr(bpf_prog_active) + : __clobber_all); +} + SEC("socket") __description("unpriv: return pointer") __success __failure_unpriv __msg_unpriv("R0 leaks addr") diff --git a/tools/testing/selftests/drivers/net/hw/tso.py b/tools/testing/selftests/drivers/net/hw/tso.py index 1b789fea8929..802bb4868046 100755 --- a/tools/testing/selftests/drivers/net/hw/tso.py +++ b/tools/testing/selftests/drivers/net/hw/tso.py @@ -187,28 +187,24 @@ def query_nic_features(cfg) -> None: cfg.wanted_features.add(f["name"]) cfg.hw_features = set() - hw_all_features_cmd = "" for f in features["hw"]["bits"]["bit"]: if f.get("value", False): - feature = f["name"] - cfg.hw_features.add(feature) - hw_all_features_cmd += f" {feature} on" - try: - ethtool(f"-K {cfg.ifname} {hw_all_features_cmd}") - except Exception as e: - ksft_pr(f"WARNING: failure enabling all hw features: {e}") - ksft_pr("partial gso feature detection may be impacted") + cfg.hw_features.add(f["name"]) # Check which features are supported via GSO partial cfg.partial_features = set() if 'tx-gso-partial' in cfg.hw_features: + seg_features = {f for f in cfg.hw_features if "segmentation" in f} + ethtool(f"-K {cfg.ifname} " + + " ".join(f"{f} on" for f in seg_features)) + ethtool(f"-K {cfg.ifname} tx-gso-partial off") no_partial = set() features = cfg.ethnl.features_get({"header": {"dev-index": cfg.ifindex}}) for f in features["active"]["bits"]["bit"]: no_partial.add(f["name"]) - cfg.partial_features = cfg.hw_features - no_partial + cfg.partial_features = seg_features - no_partial ethtool(f"-K {cfg.ifname} tx-gso-partial on") restore_wanted_features(cfg) diff --git a/tools/testing/selftests/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore index 64ac0dfa46b7..a78f894157de 100644 --- a/tools/testing/selftests/filesystems/.gitignore +++ b/tools/testing/selftests/filesystems/.gitignore @@ -5,3 +5,4 @@ fclog file_stressor anon_inode_test kernfs_test +idmapped_tmpfile diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile index 85427d7f19b9..a7ec2ba2dd83 100644 --- a/tools/testing/selftests/filesystems/Makefile +++ b/tools/testing/selftests/filesystems/Makefile @@ -2,6 +2,10 @@ CFLAGS += $(KHDR_INCLUDES) TEST_GEN_PROGS := devpts_pts file_stressor anon_inode_test kernfs_test fclog +TEST_GEN_PROGS += idmapped_tmpfile TEST_GEN_PROGS_EXTENDED := dnotify_test include ../lib.mk + +$(OUTPUT)/idmapped_tmpfile: LDLIBS += -lcap +$(OUTPUT)/idmapped_tmpfile: utils.c diff --git a/tools/testing/selftests/filesystems/idmapped_tmpfile.c b/tools/testing/selftests/filesystems/idmapped_tmpfile.c new file mode 100644 index 000000000000..bc411ab8281e --- /dev/null +++ b/tools/testing/selftests/filesystems/idmapped_tmpfile.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kselftest_harness.h" +#include "wrappers.h" +#include "utils.h" + +/* + * The test mount maps caller-visible ids [0, MAP_RANGE) onto the on-disk range + * [MAP_HOST, MAP_HOST + MAP_RANGE). An id outside [0, MAP_RANGE) therefore has + * no mapping in the mount and is not representable in the filesystem. + */ +#define MAP_HOST 10000 +#define MAP_RANGE 10000 +#define UNMAPPED 50000 + +#ifndef MOUNT_ATTR_IDMAP +#define MOUNT_ATTR_IDMAP 0x00100000 +#endif + +#ifndef __NR_mount_setattr +#define __NR_mount_setattr 442 +#endif + +static inline int sys_mount_setattr(int dfd, const char *path, + unsigned int flags, + struct mount_attr *attr, size_t size) +{ + return syscall(__NR_mount_setattr, dfd, path, flags, attr, size); +} + +/* + * Clone @path into a detached mount idmapped so that caller-visible ids + * [0, MAP_RANGE) map onto the on-disk ids [MAP_HOST, MAP_HOST + MAP_RANGE). + * Returns the mount fd, or -1 if idmapped mounts are not available. + */ +static int idmapped_clone(const char *path) +{ + struct mount_attr attr = { + .attr_set = MOUNT_ATTR_IDMAP, + }; + int fd_tree, userns_fd, ret; + + fd_tree = sys_open_tree(AT_FDCWD, path, + OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC); + if (fd_tree < 0) + return -1; + + userns_fd = get_userns_fd(MAP_HOST, 0, MAP_RANGE); + if (userns_fd < 0) { + close(fd_tree); + return -1; + } + + attr.userns_fd = userns_fd; + ret = sys_mount_setattr(fd_tree, "", AT_EMPTY_PATH, &attr, sizeof(attr)); + close(userns_fd); + if (ret) { + close(fd_tree); + return -1; + } + + return fd_tree; +} + +FIXTURE(idmapped_tmpfile) { + char dir[64]; /* non-idmapped path to the layer directory */ +}; + +FIXTURE_SETUP(idmapped_tmpfile) +{ + /* Private mount namespace so test mounts need no cleanup. */ + ASSERT_EQ(unshare(CLONE_NEWNS), 0); + ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0); + ASSERT_EQ(sys_mount("tmpfs", "/tmp", "tmpfs", 0, NULL), 0); + + snprintf(self->dir, sizeof(self->dir), "/tmp/d"); + ASSERT_EQ(mkdir(self->dir, 0777), 0); + /* World-writable so an unmapped caller still passes permission(). */ + ASSERT_EQ(chmod(self->dir, 0777), 0); +} + +FIXTURE_TEARDOWN(idmapped_tmpfile) +{ +} + +/* + * A caller whose fsuid/fsgid have no mapping in the idmapped mount must not be + * able to create an O_TMPFILE. Without the check in vfs_tmpfile() the inode + * would be created owned by (uid_t)-1 and could then be linked into the + * namespace. + */ +TEST_F(idmapped_tmpfile, unmapped_caller_is_refused) +{ + int mfd, fd; + + mfd = idmapped_clone(self->dir); + if (mfd < 0) + SKIP(return, "idmapped mounts not supported"); + + /* Become a caller outside the mount's [0, MAP_RANGE) range. */ + setfsgid(UNMAPPED); + setfsuid(UNMAPPED); + ASSERT_EQ(setfsuid(-1), UNMAPPED); + + fd = openat(mfd, ".", O_TMPFILE | O_WRONLY, 0644); + ASSERT_LT(fd, 0); + EXPECT_EQ(errno, EOVERFLOW); + if (fd >= 0) + close(fd); + + EXPECT_EQ(close(mfd), 0); +} + +/* + * A mapped caller can create an O_TMPFILE and link it into the namespace; the + * ownership round-trips through the mount idmap. This is what makes refusing + * the unmapped case above necessary in the first place. + */ +TEST_F(idmapped_tmpfile, mapped_caller_creates_and_links) +{ + char path[PATH_MAX]; + struct stat st; + int mfd, fd; + + mfd = idmapped_clone(self->dir); + if (mfd < 0) + SKIP(return, "idmapped mounts not supported"); + + /* Caller is uid/gid 0, which maps to MAP_HOST through the mount. */ + fd = openat(mfd, ".", O_TMPFILE | O_RDWR, 0600); + ASSERT_GE(fd, 0); + + ASSERT_EQ(fstat(fd, &st), 0); + EXPECT_EQ(st.st_uid, 0); + EXPECT_EQ(st.st_gid, 0); + + /* The tmpfile is linkable: splice it into the directory. */ + ASSERT_EQ(linkat(fd, "", mfd, "linked", AT_EMPTY_PATH), 0); + EXPECT_EQ(close(fd), 0); + + ASSERT_EQ(fstatat(mfd, "linked", &st, 0), 0); + EXPECT_EQ(st.st_uid, 0); + EXPECT_EQ(st.st_gid, 0); + + /* On the underlying, non-idmapped tmpfs it is stored as MAP_HOST. */ + snprintf(path, sizeof(path), "%s/linked", self->dir); + ASSERT_EQ(stat(path, &st), 0); + EXPECT_EQ(st.st_uid, MAP_HOST); + EXPECT_EQ(st.st_gid, MAP_HOST); + + EXPECT_EQ(close(mfd), 0); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/net/lib/py/utils.py b/tools/testing/selftests/net/lib/py/utils.py index 87eae79d01c1..184bb04343f6 100644 --- a/tools/testing/selftests/net/lib/py/utils.py +++ b/tools/testing/selftests/net/lib/py/utils.py @@ -44,7 +44,7 @@ class cmd: Use bkg() instead to run a command in the background. """ def __init__(self, comm, shell=None, fail=True, expect_fail=False, ns=None, - background=False, host=None, timeout=5, ksft_ready=None, + background=False, host=None, timeout=20, ksft_ready=None, ksft_wait=None): if ns: if hasattr(ns, 'user_ns_path'): @@ -113,7 +113,7 @@ class cmd: return stdout, stderr - def process(self, terminate=True, fail=None, expect_fail=False, timeout=5): + def process(self, terminate=True, fail=None, expect_fail=False, timeout=20): if fail is None: fail = not terminate diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile index e6e8cb52ab03..2c32c48db509 100644 --- a/tools/testing/selftests/vfio/Makefile +++ b/tools/testing/selftests/vfio/Makefile @@ -29,8 +29,6 @@ CFLAGS += $(EXTRA_CFLAGS) LDFLAGS += -pthread -LDLIBS += -luuid - $(TEST_GEN_PROGS): $(OUTPUT)/%: $(OUTPUT)/%.o $(LIBVFIO_O) $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $< $(LIBVFIO_O) $(LDLIBS) -o $@ diff --git a/tools/testing/selftests/vfio/lib/libvfio.mk b/tools/testing/selftests/vfio/lib/libvfio.mk index 2b8d73b7d329..67942b085068 100644 --- a/tools/testing/selftests/vfio/lib/libvfio.mk +++ b/tools/testing/selftests/vfio/lib/libvfio.mk @@ -26,6 +26,8 @@ $(LIBVFIO_O_DIRS): CFLAGS += -I$(LIBVFIO_SRCDIR)/include +LDLIBS += -luuid + $(LIBVFIO_O): $(LIBVFIO_OUTPUT)/%.o : $(LIBVFIO_SRCDIR)/%.c | $(LIBVFIO_O_DIRS) $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c index 21af54d5f4ea..3d6ca33edba4 100644 --- a/tools/testing/selftests/x86/test_shadow_stack.c +++ b/tools/testing/selftests/x86/test_shadow_stack.c @@ -873,6 +873,86 @@ static int test_uretprobe(void) return err; } +/* Keep the CALL first so the function address is exactly the probed CALL. */ +extern void uprobe_call_trigger(void); +asm (".pushsection .text\n" + ".global uprobe_call_target\n" + ".type uprobe_call_target, @function\n" + "uprobe_call_target:\n" + " ret\n" + ".size uprobe_call_target, .-uprobe_call_target\n" + + ".global uprobe_call_trigger\n" + ".type uprobe_call_trigger, @function\n" + "uprobe_call_trigger:\n" + " call uprobe_call_target\n" + " ret\n" + ".size uprobe_call_trigger, .-uprobe_call_trigger\n" + ".popsection\n" +); + +/* If CALL emulation misses the shadow stack update, this exits via SIGSEGV. */ +static int test_uprobe_call(void) +{ + const size_t attr_sz = sizeof(struct perf_event_attr); + const char *file = "/proc/self/exe"; + int fd = -1, type, err = 1; + struct perf_event_attr attr; + struct sigaction sa = {}; + ssize_t offset; + + type = determine_uprobe_perf_type(); + if (type < 0) { + if (type == -ENOENT) + printf("[SKIP]\tUprobe on CALL test, uprobes are not available\n"); + return 0; + } + + offset = get_uprobe_offset(uprobe_call_trigger); + if (offset < 0) + return 1; + + sa.sa_sigaction = segv_gp_handler; + sa.sa_flags = SA_SIGINFO; + if (sigaction(SIGSEGV, &sa, NULL)) + return 1; + + /* Setup entry uprobe through perf event interface. */ + memset(&attr, 0, attr_sz); + attr.size = attr_sz; + attr.type = type; + attr.config = 0; + attr.config1 = (__u64)(unsigned long)file; + attr.config2 = offset; + + fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */, + -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC); + if (fd < 0) + goto out; + + if (sigsetjmp(jmp_buffer, 1)) + goto out; + + if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) + goto out; + + /* + * This either segfaults and goes through sigsetjmp above + * or succeeds and we're good. + */ + uprobe_call_trigger(); + + printf("[OK]\tUprobe on CALL test\n"); + err = 0; + +out: + ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK); + signal(SIGSEGV, SIG_DFL); + if (fd >= 0) + close(fd); + return err; +} + void segv_handler_ptrace(int signum, siginfo_t *si, void *uc) { /* The SSP adjustment caused a segfault. */ @@ -1071,6 +1151,12 @@ int main(int argc, char *argv[]) goto out; } + if (test_uprobe_call()) { + ret = 1; + printf("[FAIL]\tuprobe on CALL test\n"); + goto out; + } + return ret; out: