diff --git a/arch/loongarch/include/asm/kvm_mmu.h b/arch/loongarch/include/asm/kvm_mmu.h index 153875b87b7e918e6c6212fb4426669f333e72da..76d92b9014d55a110608b9173568e54bad23b1a3 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/include/uapi/asm/kvm.h b/arch/loongarch/include/uapi/asm/kvm.h index fa461fcd0a25d8945a717fcb078c7e0e8cc46da6..29935ce87f4c4906fdb38849af137676bbafe310 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/kernel/time.c b/arch/loongarch/kernel/time.c index 46d7d40c87e38e097af74385be1e518bf95d5251..0535e5ddbfb9c9ca01b90e7bf277d9ad1f9b7944 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/kvm/intc/extioi.c b/arch/loongarch/kvm/intc/extioi.c index 801ac861c876d1893208d39d313dc2bcaecad176..440bd8733daeb351ea2ea2d4825b2519ec55aed7 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 4459ec42eb40e4eb528cd85257f1b969eb2380b5..9c68b9aee12821ba9e03edb77c236598891f6983 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 9f287b41991015c2f98fd9971f02d9ba1b73ad23..46ce3b8470ea0ad680715499bb7061158e1a1926 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/mmu.c b/arch/loongarch/kvm/mmu.c index b4b1464fc4fbde1c8c0c1beccbca7d8f0abe7893..d54b2388dfee21e42f8cbe57e3ba873783cc50d6 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 */ diff --git a/arch/loongarch/kvm/vm.c b/arch/loongarch/kvm/vm.c index 5f65610aa9fce27ce7947707dd08aca0b3c21506..8c4c3f1b4bc8ca4f3d38993486be881e1690a60a 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/arch/loongarch/power/hibernate.c b/arch/loongarch/power/hibernate.c index 1e0590542f987cd59c0bad22f938b51ad0e4f2a5..e7b7346592cb2a335c64ff23a5b2389cf63f6bf7 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); diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.c b/drivers/gpu/drm/virtio/virtgpu_drv.c index c5716fd0aed380ef9eeb554449f40b16002eaad8..c6a62ad6c1a9283226e3b8693f1755c61950c9af 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) +{ + 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) { 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 71dee622b771b3e5e5c9ac0cab286dd052051186..9518583d151273d7b6a0f0b71cdd77ee6ff1fb65 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -340,6 +340,40 @@ 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; + + /* 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. + */ + 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 +381,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) diff --git a/include/linux/virtio.h b/include/linux/virtio.h index 4cc614a38376593787d7fd2842a7b3649979ead8..d8caaefba1d8e7a28cceb1f9111d1b734e282f0a 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) diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 40e90c84463beb654281ecad331f367a0e868d0b..f60780228556d3869e9f2f96c8bdfda9f76f2e42 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,