From e0546d6b5e7fa3e8b09916cd70165e50bb405d4a Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Mon, 26 May 2025 11:21:16 +0800 Subject: [PATCH 1/6] LoongArch: Save and restore CSR.CNTC for hibernation LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICAU88 ------------------------------------------ Save and restore CSR.CNTC for hibernation which is similar to suspend. For host this is unnecessary because sched clock is ensured continuous, but for kvm guest sched clock isn't enough because rdtime.d should also be continuous. Host::rdtime.d = Host::CSR.CNTC + counter Guest::rdtime.d = Host::CSR.CNTC + Host::CSR.GCNTC + Guest::CSR.CNTC + counter so, Guest::rdtime.d = Host::rdtime.d + Host::CSR.GCNTC + Guest::CSR.CNTC To ensure Guest::rdtime.d continuous, Host::rdtime.d should be at first continuous, while Host::CSR.GCNTC / Guest::CSR.CNTC is maintained by KVM. Signed-off-by: Xianglai Li Signed-off-by: Huacai Chen Change-Id: I127c9c2d9b0a11c553dd1d46a54861215902b188 --- arch/loongarch/kernel/time.c | 2 +- arch/loongarch/power/hibernate.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index 46d7d40c87e3..0535e5ddbfb9 100644 --- a/arch/loongarch/kernel/time.c +++ b/arch/loongarch/kernel/time.c @@ -111,7 +111,7 @@ static unsigned long __init get_loops_per_jiffy(void) return lpj; } -static long init_offset __nosavedata; +static long init_offset; void save_counter(void) { diff --git a/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c index 1e0590542f98..e7b7346592cb 100644 --- a/arch/loongarch/power/hibernate.c +++ b/arch/loongarch/power/hibernate.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -14,6 +15,7 @@ struct pt_regs saved_regs; void save_processor_state(void) { + save_counter(); saved_crmd = csr_read32(LOONGARCH_CSR_CRMD); saved_prmd = csr_read32(LOONGARCH_CSR_PRMD); saved_euen = csr_read32(LOONGARCH_CSR_EUEN); @@ -26,6 +28,7 @@ void save_processor_state(void) void restore_processor_state(void) { + sync_counter(); csr_write32(saved_crmd, LOONGARCH_CSR_CRMD); csr_write32(saved_prmd, LOONGARCH_CSR_PRMD); csr_write32(saved_euen, LOONGARCH_CSR_EUEN); -- Gitee From 5502a211e3e0dae135f3df716fd758acd519fdba Mon Sep 17 00:00:00 2001 From: Song Gao Date: Fri, 23 May 2025 11:41:37 +0800 Subject: [PATCH 2/6] LoongArch: fix migrate issue LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICAU88 ------------------------------------------ when read_fault, we shoul't set the page _PAGE_WRITE. this may case nest write fault issue. Signed-off-by: Song Gao Change-Id: I443ac32d152c43635c0bafbe3da9b9479f4e546d Signed-off-by: Xianglai Li --- arch/loongarch/include/asm/kvm_mmu.h | 13 +++++++------ arch/loongarch/kvm/mmu.c | 18 ++++++------------ 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/arch/loongarch/include/asm/kvm_mmu.h b/arch/loongarch/include/asm/kvm_mmu.h index 153875b87b7e..76d92b9014d5 100644 --- a/arch/loongarch/include/asm/kvm_mmu.h +++ b/arch/loongarch/include/asm/kvm_mmu.h @@ -61,11 +61,7 @@ static inline void kvm_set_pte(kvm_pte_t *ptep, kvm_pte_t val) WRITE_ONCE(*ptep, val); } -static inline int kvm_pte_write(kvm_pte_t pte) { return pte & _PAGE_WRITE; } -static inline int kvm_record_pte_write_able(kvm_pte_t pte) -{ - return pte & KVM_RECORD_PAGE_WRITE_ABLE; -} +static inline int kvm_pte_write(kvm_pte_t pte) { return pte & KVM_RECORD_PAGE_WRITE_ABLE; } static inline int kvm_pte_dirty(kvm_pte_t pte) { return pte & _PAGE_DIRTY; } static inline int kvm_pte_young(kvm_pte_t pte) { return pte & _PAGE_ACCESSED; } static inline int kvm_pte_huge(kvm_pte_t pte) { return pte & _PAGE_HUGE; } @@ -82,7 +78,12 @@ static inline kvm_pte_t kvm_pte_mkold(kvm_pte_t pte) static inline kvm_pte_t kvm_pte_mkdirty(kvm_pte_t pte) { - return pte | _PAGE_DIRTY; + return pte | _PAGE_DIRTY | _PAGE_WRITE; +} + +static inline kvm_pte_t kvm_pte_mkwrite(kvm_pte_t pte) +{ + return pte | KVM_RECORD_PAGE_WRITE_ABLE; } static inline kvm_pte_t kvm_pte_mkclean(kvm_pte_t pte) diff --git a/arch/loongarch/kvm/mmu.c b/arch/loongarch/kvm/mmu.c index b4b1464fc4fb..d54b2388dfee 100644 --- a/arch/loongarch/kvm/mmu.c +++ b/arch/loongarch/kvm/mmu.c @@ -538,8 +538,10 @@ bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) * _PAGE_DIRTY since gpa has already recorded as dirty page */ prot_bits |= __WRITEABLE & *ptep & pte_val(range->arg.pte); - if (prot_bits & _PAGE_WRITE) - prot_bits |= KVM_RECORD_PAGE_WRITE_ABLE; + if (kvm_pte_dirty(prot_bits)) { + prot_bits = kvm_pte_mkclean(prot_bits); + prot_bits = kvm_pte_mkwrite(prot_bits); + } kvm_set_pte(ptep, kvm_pfn_pte(pfn, __pgprot(prot_bits))); return true; @@ -605,15 +607,7 @@ static int kvm_map_page_fast(struct kvm_vcpu *vcpu, unsigned long gpa, bool writ /* Track access to pages marked old */ new = kvm_pte_mkyoung(*ptep); - /* We restore the write property of - * the page table entry according to - * KVM_RECORD_PAGE_WRITE_ABLE - */ - if (kvm_record_pte_write_able(new)) - new |= _PAGE_WRITE; - /* call kvm_set_pfn_accessed() after unlock */ - if (write && !kvm_pte_dirty(new)) { if (!kvm_pte_write(new)) { ret = -EFAULT; @@ -918,9 +912,9 @@ static int kvm_map_page(struct kvm_vcpu *vcpu, unsigned long gpa, bool write) * to record it to restore the write attribute of the page entry, * in the fast path kvm_map_page_fast for page table processing */ - prot_bits |= _PAGE_WRITE | KVM_RECORD_PAGE_WRITE_ABLE; + prot_bits = kvm_pte_mkwrite(prot_bits); if (write) - prot_bits |= __WRITEABLE; + prot_bits = kvm_pte_mkdirty(prot_bits); } /* Disable dirty logging on HugePages */ -- Gitee From 98cc199fed73e0dffe85d9d9f6450f9ebb270511 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Mon, 26 May 2025 15:55:54 +0800 Subject: [PATCH 3/6] LoongArch: sync kvm head file from upstream LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICAU88 ------------------------------------------ The local interrupt controller simulation header file is inconsistent with the upstream header file. To ensure uapi compatibility, the upstream interrupt controller simulation header file is now synchronized. Signed-off-by: Xianglai Li Change-Id: I15b5f15d27bddb2ba7f497a90a78e879ad4f3334 --- arch/loongarch/include/uapi/asm/kvm.h | 17 +++++++---------- arch/loongarch/kvm/intc/extioi.c | 2 +- arch/loongarch/kvm/intc/ipi.c | 2 +- arch/loongarch/kvm/intc/pch_pic.c | 2 +- arch/loongarch/kvm/vm.c | 2 -- include/uapi/linux/kvm.h | 12 ++++++------ 6 files changed, 16 insertions(+), 21 deletions(-) diff --git a/arch/loongarch/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h index fa461fcd0a25..29935ce87f4c 100644 --- a/arch/loongarch/include/uapi/asm/kvm.h +++ b/arch/loongarch/include/uapi/asm/kvm.h @@ -135,26 +135,23 @@ struct kvm_iocsr_entry { #define KVM_IRQCHIP_NUM_PINS 64 #define KVM_MAX_CORES 256 -#define KVM_LOONGARCH_VM_HAVE_IRQCHIP 0x40000001 -#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000002 +#define KVM_DEV_LOONGARCH_IPI_GRP_REGS 0x40000001 -#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000003 +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS 0x40000002 -#define KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS 0x40000006 +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_SW_STATUS 0x40000003 #define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_NUM_CPU 0x0 #define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_FEATURE 0x1 #define KVM_DEV_LOONGARCH_EXTIOI_SW_STATUS_STATE 0x2 -#define KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL 0x40000007 +#define KVM_DEV_LOONGARCH_EXTIOI_GRP_CTRL 0x40000004 #define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_NUM_CPU 0x0 #define KVM_DEV_LOONGARCH_EXTIOI_CTRL_INIT_FEATURE 0x1 #define KVM_DEV_LOONGARCH_EXTIOI_CTRL_LOAD_FINISHED 0x3 - -#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000004 -#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 - -#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 +#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_REGS 0x40000005 +#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000006 +#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0 #endif /* __UAPI_ASM_LOONGARCH_KVM_H */ diff --git a/arch/loongarch/kvm/intc/extioi.c b/arch/loongarch/kvm/intc/extioi.c index 801ac861c876..440bd8733dae 100644 --- a/arch/loongarch/kvm/intc/extioi.c +++ b/arch/loongarch/kvm/intc/extioi.c @@ -931,7 +931,7 @@ static struct kvm_device_ops kvm_loongarch_extioi_dev_ops = { int kvm_loongarch_register_extioi_device(void) { return kvm_register_device_ops(&kvm_loongarch_extioi_dev_ops, - KVM_DEV_TYPE_LA_EXTIOI); + KVM_DEV_TYPE_LOONGARCH_EIOINTC); } int kvm_loongarch_reset_extioi(struct kvm *kvm) diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c index 4459ec42eb40..9c68b9aee128 100644 --- a/arch/loongarch/kvm/intc/ipi.c +++ b/arch/loongarch/kvm/intc/ipi.c @@ -534,7 +534,7 @@ static struct kvm_device_ops kvm_loongarch_ipi_dev_ops = { int kvm_loongarch_register_ipi_device(void) { return kvm_register_device_ops(&kvm_loongarch_ipi_dev_ops, - KVM_DEV_TYPE_LA_IPI); + KVM_DEV_TYPE_LOONGARCH_IPI); } int kvm_loongarch_reset_ipi(struct kvm_vcpu *vcpu) diff --git a/arch/loongarch/kvm/intc/pch_pic.c b/arch/loongarch/kvm/intc/pch_pic.c index 9f287b419910..46ce3b8470ea 100644 --- a/arch/loongarch/kvm/intc/pch_pic.c +++ b/arch/loongarch/kvm/intc/pch_pic.c @@ -536,7 +536,7 @@ static struct kvm_device_ops kvm_loongarch_pch_pic_dev_ops = { int kvm_loongarch_register_pch_pic_device(void) { return kvm_register_device_ops(&kvm_loongarch_pch_pic_dev_ops, - KVM_DEV_TYPE_LA_IOAPIC); + KVM_DEV_TYPE_LOONGARCH_PCHPIC); } int kvm_loongarch_reset_pch(struct kvm *kvm) diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c index 5f65610aa9fc..8c4c3f1b4bc8 100644 --- a/arch/loongarch/kvm/vm.c +++ b/arch/loongarch/kvm/vm.c @@ -153,8 +153,6 @@ static int kvm_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) switch (attr->group) { case KVM_LOONGARCH_VM_FEAT_CTRL: return kvm_vm_feature_has_attr(kvm, attr); - case KVM_LOONGARCH_VM_HAVE_IRQCHIP: - return 0; default: return -ENXIO; } diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 40e90c84463b..f60780228556 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1482,12 +1482,12 @@ enum kvm_device_type { #define KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_ARM_PV_TIME KVM_DEV_TYPE_RISCV_AIA, #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA - KVM_DEV_TYPE_LA_IOAPIC = 0x100, -#define KVM_DEV_TYPE_LA_IOAPIC KVM_DEV_TYPE_LA_IOAPIC - KVM_DEV_TYPE_LA_IPI, -#define KVM_DEV_TYPE_LA_IPI KVM_DEV_TYPE_LA_IPI - KVM_DEV_TYPE_LA_EXTIOI, -#define KVM_DEV_TYPE_LA_EXTIOI KVM_DEV_TYPE_LA_EXTIOI + KVM_DEV_TYPE_LOONGARCH_IPI, +#define KVM_DEV_TYPE_LOONGARCH_IPI KVM_DEV_TYPE_LOONGARCH_IPI + KVM_DEV_TYPE_LOONGARCH_EIOINTC, +#define KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_EIOINTC + KVM_DEV_TYPE_LOONGARCH_PCHPIC, +#define KVM_DEV_TYPE_LOONGARCH_PCHPIC KVM_DEV_TYPE_LOONGARCH_PCHPIC KVM_DEV_TYPE_MAX, -- Gitee From 7ecbd5f9a9759aecda982052c2f51d7253f1b324 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 8 Aug 2024 10:51:41 +0300 Subject: [PATCH 4/6] virtio: break and reset virtio devices on device_shutdown() mainline inclusion from mainline-v6.15-rc1 commit 8bd2fa086a04886798b505f28db4002525895203 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICAU88 CVE: NA -------------------------------- Hongyu reported a hang on kexec in a VM. QEMU reported invalid memory accesses during the hang. Invalid read at addr 0x102877002, size 2, region '(null)', reason: rejected Invalid write at addr 0x102877A44, size 2, region '(null)', reason: rejected ... It was traced down to virtio-console. Kexec works fine if virtio-console is not in use. The issue is that virtio-console continues to write to the MMIO even after underlying virtio-pci device is reset. Additionally, Eric noticed that IOMMUs are reset before devices, if devices are not reset on shutdown they continue to poke at guest memory and get errors from the IOMMU. Some devices get wedged then. The problem can be solved by breaking all virtio devices on virtio bus shutdown, then resetting them. Tested-by: Eric Auger Acked-by: Jason Wang Signed-off-by: Michael S. Tsirkin Signed-off-by: Xianglai Li Change-Id: I5f1f050c48cd74fc0b0b759cc7287aa939845b32 --- drivers/virtio/virtio.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 71dee622b771..b8f76128363f 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -340,6 +340,34 @@ static void virtio_dev_remove(struct device *_d) of_node_put(dev->dev.of_node); } +static void virtio_dev_shutdown(struct device *_d) +{ + struct virtio_device *dev = dev_to_virtio(_d); + struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); + + /* + * Stop accesses to or from the device. + * We only need to do it if there's a driver - no accesses otherwise. + */ + if (!drv) + return; + + /* + * Some devices get wedged if you kick them after they are + * reset. Mark all vqs as broken to make sure we don't. + */ + virtio_break_device(dev); + /* + * Guarantee that any callback will see vq->broken as true. + */ + virtio_synchronize_cbs(dev); + /* + * As IOMMUs are reset on shutdown, this will block device access to memory. + * Some devices get wedged if this happens, so reset to make sure it does not. + */ + dev->config->reset(dev); +} + static struct bus_type virtio_bus = { .name = "virtio", .match = virtio_dev_match, @@ -347,6 +375,7 @@ static struct bus_type virtio_bus = { .uevent = virtio_uevent, .probe = virtio_dev_probe, .remove = virtio_dev_remove, + .shutdown = virtio_dev_shutdown, }; int register_virtio_driver(struct virtio_driver *driver) -- Gitee From 5ae40b688afed899369c52ea20d79c5aa5d65dad Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 10 Apr 2025 03:16:26 -0400 Subject: [PATCH 5/6] virtgpu: don't reset on shutdown mainline inclusion from mainline-v6.15-rc4 commit 183a08715af1491d381b4e22efd61578fbe05fa5 category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICAU88 CVE: NA -------------------------------- It looks like GPUs are used after shutdown is invoked. Thus, breaking virtio gpu in the shutdown callback is not a good idea - guest hangs attempting to finish console drawing, with these warnings: [ 20.504464] WARNING: CPU: 0 PID: 568 at drivers/gpu/drm/virtio/virtgpu_vq.c:358 virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu] [ 20.505685] Modules linked in: nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 rfkill ip_set nf_tables nfnetlink vfat fat intel_rapl_msr intel_rapl_common intel_uncore_frequency_common nfit libnvdimm kvm_intel kvm rapl iTCO_wdt iTCO_vendor_support virtio_gpu virtio_dma_buf pcspkr drm_shmem_helper i2c_i801 drm_kms_helper lpc_ich i2c_smbus virtio_balloon joydev drm fuse xfs libcrc32c ahci libahci crct10dif_pclmul crc32_pclmul crc32c_intel libata virtio_net ghash_clmulni_intel net_failover virtio_blk failover serio_raw dm_mirror dm_region_hash dm_log dm_mod [ 20.511847] CPU: 0 PID: 568 Comm: kworker/0:3 Kdump: loaded Tainted: G W ------- --- 5.14.0-578.6675_1757216455.el9.x86_64 #1 [ 20.513157] Hardware name: Red Hat KVM/RHEL, BIOS edk2-20241117-3.el9 11/17/2024 [ 20.513918] Workqueue: events drm_fb_helper_damage_work [drm_kms_helper] [ 20.514626] RIP: 0010:virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu] [ 20.515332] Code: 00 00 48 85 c0 74 0c 48 8b 78 08 48 89 ee e8 51 50 00 00 65 ff 0d 42 e3 74 3f 0f 85 69 ff ff ff 0f 1f 44 00 00 e9 5f ff ff ff <0f> 0b e9 3f ff ff ff 48 83 3c 24 00 74 0e 49 8b 7f 40 48 85 ff 74 [ 20.517272] RSP: 0018:ff34f0a8c0787ad8 EFLAGS: 00010282 [ 20.517820] RAX: 00000000fffffffb RBX: 0000000000000000 RCX: 0000000000000820 [ 20.518565] RDX: 0000000000000000 RSI: ff34f0a8c0787be0 RDI: ff218bef03a26300 [ 20.519308] RBP: ff218bef03a26300 R08: 0000000000000001 R09: ff218bef07224360 [ 20.520059] R10: 0000000000008dc0 R11: 0000000000000002 R12: ff218bef02630028 [ 20.520806] R13: ff218bef0263fb48 R14: ff218bef00cb8000 R15: ff218bef07224360 [ 20.521555] FS: 0000000000000000(0000) GS:ff218bef7ba00000(0000) knlGS:0000000000000000 [ 20.522397] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 20.522996] CR2: 000055ac4f7871c0 CR3: 000000010b9f2002 CR4: 0000000000771ef0 [ 20.523740] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 20.524477] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400 [ 20.525223] PKRU: 55555554 [ 20.525515] Call Trace: [ 20.525777] [ 20.526003] ? show_trace_log_lvl+0x1c4/0x2df [ 20.526464] ? show_trace_log_lvl+0x1c4/0x2df [20.526925] ? virtio_gpu_queue_fenced_ctrl_buffer+0x82/0x2c0 [virtio_gpu] [ 20.527643] ? virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu] [ 20.528282] ? __warn+0x7e/0xd0 [ 20.528621] ? virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu] [ 20.529256] ? report_bug+0x100/0x140 [ 20.529643] ? handle_bug+0x3c/0x70 [ 20.530010] ? exc_invalid_op+0x14/0x70 [ 20.530421] ? asm_exc_invalid_op+0x16/0x20 [ 20.530862] ? virtio_gpu_queue_ctrl_sgs+0x236/0x290 [virtio_gpu] [ 20.531506] ? virtio_gpu_queue_ctrl_sgs+0x174/0x290 [virtio_gpu] [ 20.532148] virtio_gpu_queue_fenced_ctrl_buffer+0x82/0x2c0 [virtio_gpu] [ 20.532843] virtio_gpu_primary_plane_update+0x3e2/0x460 [virtio_gpu] [ 20.533520] drm_atomic_helper_commit_planes+0x108/0x320 [drm_kms_helper] [ 20.534233] drm_atomic_helper_commit_tail+0x45/0x80 [drm_kms_helper] [ 20.534914] commit_tail+0xd2/0x130 [drm_kms_helper] [ 20.535446] drm_atomic_helper_commit+0x11b/0x140 [drm_kms_helper] [ 20.536097] drm_atomic_commit+0xa4/0xe0 [drm] [ 20.536588] ? __pfx___drm_printfn_info+0x10/0x10 [drm] [ 20.537162] drm_atomic_helper_dirtyfb+0x192/0x270 [drm_kms_helper] [20.537823] drm_fbdev_shmem_helper_fb_dirty+0x43/0xa0 [drm_shmem_helper] [ 20.538536] drm_fb_helper_damage_work+0x87/0x160 [drm_kms_helper] [ 20.539188] process_one_work+0x194/0x380 [ 20.539612] worker_thread+0x2fe/0x410 [ 20.540007] ? __pfx_worker_thread+0x10/0x10 [ 20.540456] kthread+0xdd/0x100 [ 20.540791] ? __pfx_kthread+0x10/0x10 [ 20.541190] ret_from_fork+0x29/0x50 [ 20.541566] [ 20.541802] ---[ end trace 0000000000000000 ]--- It looks like the shutdown is called in the middle of console drawing, so we should either wait for it to finish, or let drm handle the shutdown. This patch implements this second option: Add an option for drivers to bypass the common break+reset handling. As DRM is careful to flush/synchronize outstanding buffers, it looks like GPU can just have a NOP there. Reviewed-by: Eric Auger Tested-by: Eric Auger Fixes: 8bd2fa086a04 ("virtio: break and reset virtio devices on device_shutdown()") Cc: Eric Auger Cc: Jocelyn Falempe Signed-off-by: Michael S. Tsirkin Signed-off-by: Xianglai Li Change-Id: I67ee2081bcb4efe30630bb00621603071cfcb466 --- drivers/gpu/drm/virtio/virtgpu_drv.c | 9 +++++++++ drivers/virtio/virtio.c | 6 ++++++ include/linux/virtio.h | 3 +++ 3 files changed, 18 insertions(+) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index c5716fd0aed3..6fefcafd7026 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -123,6 +123,14 @@ static void virtio_gpu_remove(struct virtio_device *vdev) drm_dev_put(dev); } +static void virtio_gpu_shutdown(struct virtio_device *vdev) +{ + /* + * drm does its own synchronization on shutdown. + * Do nothing here, opt out of device reset. + */ +} + static void virtio_gpu_config_changed(struct virtio_device *vdev) { struct drm_device *dev = vdev->priv; @@ -158,6 +166,7 @@ static struct virtio_driver virtio_gpu_driver = { .id_table = id_table, .probe = virtio_gpu_probe, .remove = virtio_gpu_remove, + .shutdown = virtio_gpu_shutdown, .config_changed = virtio_gpu_config_changed }; diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index b8f76128363f..9518583d1512 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -352,6 +352,12 @@ static void virtio_dev_shutdown(struct device *_d) if (!drv) return; + /* If the driver has its own shutdown method, use that. */ + if (drv->shutdown) { + drv->shutdown(dev); + return; + } + /* * Some devices get wedged if you kick them after they are * reset. Mark all vqs as broken to make sure we don't. diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 4cc614a38376..d8caaefba1d8 100644 --- a/include/linux/virtio.h +++ b/include/linux/virtio.h @@ -178,6 +178,8 @@ size_t virtio_max_dma_size(const struct virtio_device *vdev); * changes; may be called in interrupt context. * @freeze: optional function to call during suspend/hibernation. * @restore: optional function to call on resume. + * @shutdown: synchronize with the device on shutdown. If provided, replaces + * the virtio core implementation. */ struct virtio_driver { struct device_driver driver; @@ -193,6 +195,7 @@ struct virtio_driver { void (*config_changed)(struct virtio_device *dev); int (*freeze)(struct virtio_device *dev); int (*restore)(struct virtio_device *dev); + void (*shutdown)(struct virtio_device *dev); }; static inline struct virtio_driver *drv_to_virtio(struct device_driver *drv) -- Gitee From 309ad6bee783f53191fbebe3e5228788d2020a10 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Tue, 20 May 2025 11:54:58 +0800 Subject: [PATCH 6/6] drm/virtio: implement virtio_gpu_shutdown LoongArch inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/ICAU88 ------------------------------------------ Calling drm_dev_unplug() is the drm way to say the device is gone and can not be accessed any more. Cc: Michael S. Tsirkin Signed-off-by: Gerd Hoffmann Reviewed-by: Eric Auger Tested-by: Eric Auger Signed-off-by: Xianglai Li Change-Id: Ib23f2754d314ea61c4a341bcff9dcd05bdcea28d --- drivers/gpu/drm/virtio/virtgpu_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index 6fefcafd7026..c6a62ad6c1a9 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.c +++ b/drivers/gpu/drm/virtio/virtgpu_drv.c @@ -125,10 +125,10 @@ static void virtio_gpu_remove(struct virtio_device *vdev) static void virtio_gpu_shutdown(struct virtio_device *vdev) { - /* - * drm does its own synchronization on shutdown. - * Do nothing here, opt out of device reset. - */ + struct drm_device *dev = vdev->priv; + + /* stop talking to the device */ + drm_dev_unplug(dev); } static void virtio_gpu_config_changed(struct virtio_device *vdev) -- Gitee